0
votes

I’m new to angular framework and I have a performance problem with nested *ngFor loops used to display hierarchical data.

  1. *ngFor - 10 Items ( Level 1 ) extension panel for each item
  2. *ngFor 10 Items ( Level 2 ) grid list to display the content
  3. *ngFor 5 Items (Level 3 ) 5 button toggles and 2 select controls

To avoid loading all the data, I’m setting the collection for 2nd *ngFor based on current opened panel from level 1.

The entire page is very slow when I’m expanding a panel or when I’m trying to press a button toggle. Note: I do not change the collections with these actions.

For debugging, I put a function in each ngFor to return the collections. I saw that each time I press a button toggle, angular is redoing all the iterations in all *ngFor directives multiple times.

I don’t understand why all the iterations are necessary each time I change a control. How can I improve performance in this case?

Code sample reproducing the problem on stackblitz!

2
Use trackby function, check this:angular.io/api/common/NgForOf#description - Chellappan வ
Thanks @Chellappan, but angular is still doing all the *ngFor iteration when I change a control. If I understand correctly, trackBy is used when you add/remove items in collection. - James

2 Answers

1
votes

you can improve a bit the perfomance using a variable "index" and make "content" visible only if this value is the selected accordeaon

<!--I put the *ngFor in the own mat-expansion-panel-->
<mat-expansion-panel 
          *ngFor="let itemLevel1 of this.rootItem.children;let i=index"
          [expanded]="false" 
           <!--see that pass, itemLevel1 and "i"-->
          (opened)="onOpenLevel1Panel(itemLevel1,i)">
    <mat-expansion-panel-header>
      ...
    </mat-expansion-panel-header>   
    <ng-container *ngIf="i==index" >  
         <div *ngFor="let itemLevel2 of this.selectedItemChildren;">
            ....
         </div>
    </ng-container>
<mat-expansion-panel>

In OpenLevel1Panel, we use the variable index

  index:number=-1;

  onOpenLevel1Panel(selectedItem: Item,index:number): void {
    this.selectedItemChildren = selectedItem.children;
    this.index=index;
  }

FutherMore, I think that the "options" are the real cause to slow the app

0
votes

You pointed out a real problem, nested data. *ngFor built for simple flat iterations. From here you can try to combine some tricks and techniques:

  1. Optimize rendering by using 'trackby'. It will help but can't solve it.
  2. Try to flat data by using 'smart-dumb' components approach, see this example
  3. lazy handle each level separately, You can even handle any recursive deep level (click opens new level)
  4. Optimize rendering by using virtual scroll, this will not render invisible data, good for long lists.