symfony
symfony

Reputation: 43

how can i use a function in ngIf condition Angular

i have 2 functions

loadItems(): void {
this.service.query().subscribe((res: HttpResponse<Item[]>) => 
 (this.items = res.body || []));
 }
 
loadAuditByItem(item: Item) {
this.service.auditByItem(item.id!).subscribe((res: HttpResponse<ItemAudit[]>) => 
(this.auditByItem = res.body || []));
 }

i want to display informations from both loadItems() and loadAuditByItem() at the same page i managed to display the name and description from loadItems() but i need to display "createdBy" from loadAuditByItem(item)

<div *ngFor="let item of items">
    <div *ngIf="loadAuditByItem(item)">
        <span>Name: {{ item.name}}</span>
        <span>Description : {{ item.description }}</span>
        <span>Created by: {{ auditByItem .createdBy}}</span>
    </div>
</div>

Upvotes: 0

Views: 1201

Answers (2)

Tarek B
Tarek B

Reputation: 495

Having a function call in ngIf is very bad for performance (you could add a console.log and check your console to see how many times it is been called) instead you could use Pipes, that had been said let me give you a solution for your use case:

import { forkJoin, Observable, of, Subject } from "rxjs";
import { map, switchMap } from "rxjs/operators";
...

  public items$: Observable<Item[]>;

...

  loadItems(): void {
    // please consider to edit your backend API to return all data in one API call
    // since this nested calls will lead to N+1 calls problem.

    this.items$ = this.service.query().pipe(
      map((res: HttpResponse<[]>) => res.body || []),
      switchMap((items: []) => {

        if (items.length === 0) {
          return of([]);
        }

        return forkJoin(
          items.map((item: any) =>
            this.service.auditByItem(item.id).pipe(
              map(audit => {
                item.audit = audit;
                return item;
              })
            )
          )
        );
      })
    );
  }
<div *ngFor="let item of (items$ | async)">
    <div>
        <span>Name: {{ item.name}}</span>
        <span>Description : {{ item.description }}</span>
        <span>Created by: {{ item.audit.createdBy}}</span>
    </div>
</div>

Bonus: It is not good to expose HttpResponse from the service, and it is better to return only the Item[] and encapsulate the HttpResponse there.

Upvotes: 1

Marco
Marco

Reputation: 1093

I would have return the Observable so that *ngIf handle the subscription with the AsyncPipe.

public loadAuditByItem(item: Item): Observable<any> {
    return this.service.auditByItem(item.id!);
}
<div *ngFor="let item of items">
    <div *ngIf="loadAuditByItem(item) | async as audit">
        <span>Name: {{ item.name }}</span>
        <span>Description : {{ item.description }}</span>
        <span>Created by: {{ audit.createdBy }}</span>
    </div>
</div>

Upvotes: 1

Related Questions