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.