Search code examples
angularhtml-tablengrx

Angular re-render only changed row in a table with ngrx


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.


Solution

  • 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