The problem
- 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);
- 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
- 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
})
);
}
- 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 :)
Edit, after question updated:
Iterating and calling functions in the template is not a good practice as I mentioned above, so basically the best would be to put it into the ngOnInit and init everything there so it will not refetch when it rerenders:
ts file
cargoData: Observable<any[]>[];
ngOnInit() {
this.cargoData = this.cargos.map(cargo => this.getTrucksByUserIdAndRules(cargo.id));
}
html file
<mat-card *ngFor="let trucks of cargoData" class="cont-mat">
...
<mat-checkbox *ngFor="let truck of (trucks | async)" formControlName="truckId">{{truck.regNumber}}</mat-checkbox>
getTrucksByUserIdAndRules(cargo.id)? You need to add those details as it will be tough to give you any answer without it. It seems you are giving object to thengFor.