2

I am using NGRX to load data from remote api, into an array, and after render the array in a classic HTML table. Partially the code looks like this:

  ngOnInit() {
    this.store
      .select(
        createSelector(
          (state: AppState) => state.userProperties,
          (propObject: UserProperties) => propObject
        )
      )
      .pipe(takeUntil(this.destroyed$))
      .subscribe(({properties, total }) => {
        this.propertyList = properties;
        this.totalFound = total;
      })

And render code:

      <tbody>
        <ng-container *ngFor="let row of propertyList">
          <tr>
            <td>
            </td>
            <td class="limited">{{ row.id }}</td>
            <td class="limited">{{ categoryLabels[row.category] | _: trans.lang }}</td>
            <td class="limited">{{ contractLabels[row.contract_type] | _: trans.lang }}</td>
            <td class="limited">{{ row.price }}</td>
            <td class="limited">{{ row.city }}</td>
            <td class="limited">
            </td>
            <td>
              <div class="table-actions">
                <button (click)="editProperty(row.id)" class="button button-icon">
                  <edit-icon></edit-icon>
                </button>
                <button *ngIf="row.deleted === 0" (click)="archiveProperty(row.id)" title="Delete this property"
                  class="button button-icon">
                  <img src="/assets/images/icons/delete-red.svg" />
                </button>
                <button (click)="toggleExpand(row.id)" class="button button-icon btn-expand">
                  <expand-icon [expanded]="expandedElements[row.id]"></expand-icon>
                </button>
              </div>
            </td>
          </tr>
        </ng-container>

The issue I notice if that if I change a row, example I click setStatus, which changes a row of the array, all the table renders again (causing some flickering).

Is there a way to tell angular to render only the rows of the array which have changed?

Solution (thanks to @Dmytro Demyanenko): Add trackBy to the ngFor:

<ng-container *ngFor="let row of propertyList; trackBy: trackByFn">

And define trackBy function:

  trackByFn(index, row) {
    return JSON.stringify(row);
  }

Angular will re-render the ngFor loop element only if the trackBy function returns a different value from the last one returned. In my case some data in the row might change and then I need to re-render.

albanx
  • 6,193
  • 9
  • 67
  • 97

1 Answers1

4

Yes, you can do this. You can use trackBy for ngFor. This is the way to tell angular to render only the rows of the array which have changed.

Please, read more about this here How to use trackBy with ngFor or here to see an example Explain ngFor trackBy in Angular

  • 1
    Didn't know about this TIL, thanks. It worked at best, my trackBy function returns `return JSON.stringify(row);` Angular compares the different values returned by this function to decide if update the row or not. – albanx Oct 29 '22 at 14:48