Home > OS >  Angular - function in *ngFor
Angular - function in *ngFor

Time:09-23

I have *ngFor in my template:

<mat-checkbox *ngFor="let truck of getTrucksByUserIdAndRules(cargo.id)" formControlName="truckId">{{truck.regNumber}}</mat-checkbox>

component function:

getTrucksByUserIdAndRules(cargoId: string) {
   return this.cargosService.getTrucksByUserIdAndRules(this.userId, cargoId);
  }

and cargoService function:

getTrucksByUserIdAndRules(userId: string, cargoId: string): Observable<any> {
    return this.http.get(BACKEND_URL_2   "getTrucksByUserIdAndRules/"   userId   "/"   cargoId);
  }

I'm getting error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

I want to fetch only specific trucks for each cargo.id. That's why I'm using function getTrucksByUserIdAndRules(cargo.id) instead of defined array. Thank you for your time, any other solution than this is welcome.

CodePudding user response:

The problem

  1. Your response you are getting from the API seems be not an array which is required for an iteration. What is the response from this request?
return this.http.get(BACKEND_URL_2   "getTrucksByUserIdAndRules/"   userId   "/"   cargoId);
  1. Since your request returns an Observable, which is async, you need to add an async pipe in your template. getTrucksByUserIdAndRules(cargo.id) is an Observable
*ngFor="let truck of getTrucksByUserIdAndRules(cargo.id)"

The solution

  1. You need to check first what your response value is and then map it to an array if necessary. This is done via a rxjs pipe. You need to modify your service method. It would look like this:

Docs to pipe: https://rxjs.dev/guide/operators

getTrucksByUserIdAndRules(userId: string, cargoId: string): Observable<any> {
  const url = BACKEND_URL_2   "getTrucksByUserIdAndRules/"   userId   "/"   cargoId;
  return this.http.get(url).pipe(
     map(response => {
        // console.log(response) <- check here your value, first
        return response.value // this is just an example here, but you need to return an array at this point
     })
  );
}
  1. You need to add the async pipe: https://angular.io/api/common/AsyncPipe

For that, update your template like this:

<mat-checkbox *ngFor="let truck of (getTrucksByUserIdAndRules(cargo.id) | async)" formControlName="truckId">{{truck.regNumber}}</mat-checkbox>

Notes:

  • I would recommend to put the result from the request into a seperate variable (attribute) of the component instead of calling the method directly in the template to make it look more clean. Component method:
trucks$: Observable<any[]>;
getTrucksByUserIdAndRules(cargoId: string) {
   this.trucks$ = 
  this.cargosService.getTrucksByUserIdAndRules(this.userId, cargoId)
  return this.trucks$;
}

Template:

<mat-checkbox *ngFor="let truck of trucks$" formControlName="truckId">{{truck.regNumber}}</mat-checkbox>
  • Also use the exact type instead of any since this will create problems in the future as the application grows.

If you still have problems, don't hesitate to ask. Here to help :)

CodePudding user response:

You need to add <any> after the get in the cargoService component

getTrucksByUserIdAndRules(userId: string, cargoId: string): Observable<any> {
    return this.http.get<any>(BACKEND_URL_2   "getTrucksByUserIdAndRules/"   userId   "/"   cargoId);
  }

This way it will check that is an object that has a length and can do the for.

Also, try to add the .suscribe() to the function and adding the result to a variable so you can operate with that variable:

        getTrucksByUserIdAndRules(cargoId: string) {
          return this.cargosService.getTrucksByUserIdAndRules(this.userId, cargoId).suscribe(
             res=> this.variable = res //Try checking what it gets. Try operating with the variable instead
          );
       }
  • Related