2

When ngFor should render 7600 items which are strings, then performance are very slow, browser freeze on couple of seconds.

Is somehow possible to improve performance of ngFor?

ngFor code:

  <ul *ngIf="isOpen"
    class="nano-drop-down-list"
    dropdownMenu>
    <li class="nano-f-r nano-f-30">
        <input [(ngModel)]="searchString"
               class="nano-f nano-p-0_10 nano-bc-ws hover-effect"
               placeholder="Search..." type="text"/>
    </li>

    <!-- ngFor which should be improved -->
    <li *ngFor="let option of arrayOfOptions | nanoSearchByKey:searchString:displayProperty;"
        [ngClass]="{'active':isOptionSelected(option[valueProperty])}"
        class="nano-f-r nano-f-30 nano-bc-ws hover-effect">
        <button (click)="handleClickOnOption(option[valueProperty]);"
                type="button"
                class="nano-f-c nano-f nano-p-0_10 nano-overflow-h">
            <div class="nano-f-r nano-f">
                <span class="nano-m-aaa0 nano-overflow-e">
                    {{ option[displayProperty] }}
                </span>
                <div *ngIf="isMultiple"
                     class="nano-f-r nano-f-30">
                    <i *ngIf="isOptionSelected(option[valueProperty])"
                       class="fa fa-check nano-m-a"
                       aria-hidden="true"></i>
                </div>
            </div>
        </button>
    </li>
</ul>
James Delaney
  • 1,765
  • 1
  • 17
  • 36

2 Answers2

10

NgForOf in Angular 6 comes with the option to override the track by function (source). It allows you to choose what property/condition angular should check changes against.

For that, simply add a method to your component like so:

trackByFn(index, item) {
  return item.someUniqueIdentifier;
  // or if you have no unique identifier:
  // return index;
}

Whereas in your components HTML you change the loop to

<li *ngFor="let option of arrayOfOptions | nanoSearchByKey:searchString:displayProperty; trackBy: trackByFn"
        [ngClass]="{'active':isOptionSelected(option[valueProperty])}"
        class="nano-f-r nano-f-30 nano-bc-ws hover-effect">

Angular will automatically pass the current index, as well as the current item to the function.

Here's a good post with a more concrete example and further information (Thanks @Pedro Arantes).

Philipp Meissner
  • 5,273
  • 5
  • 34
  • 59
1

The solution with the trackBy and the function is correct.

My solution is the follow:

<li *ngFor="let option of arrayOfOptions | nanoSearchByKey:searchString:displayProperty;let i = index;trackBy: i" [ngClass]="{'active':isOptionSelected(option[valueProperty])}"
        class="nano-f-r nano-f-30 nano-bc-ws hover-effect">

using

let i = index; trackBy: i 

in order to avoid to have a function