PrimeNG Table lazy loading first index desynchronization when totalRecords changes mid-request
0 reputation · 27 Jan 2025, 12:51 UTC
0 reputation · 27 Jan 2025, 12:51 UTC
When using PrimeNG Table with [lazy]="true", the component relies on the first and rows parameters from LazyLoadEvent to request the correct page slice from the server. A race condition arises if the total record count changes between the moment the request is sent and the response arrives — for example, when another user deletes records or a background job archives data.
The totalRecords bound to the table may no longer match the server's actual count at response time. PrimeNG does not document how the internal first index should be reconciled when the returned dataset is smaller than expected or when the last page becomes empty. The component may retain a stale first value that points beyond the new last record, leaving the table blank until manual navigation occurs.
Applications that implement optimistic UI updates or operate in high-concurrency environments need a deterministic strategy for this scenario. The current behavior appears to depend on whether totalRecords is updated before or after the lazy load callback completes.
first to the new last page when totalRecords decreases during a pending lazy load?totalRecords atomically with the data array to avoid a flash of empty state?totalRecords and first values for the client to adopt unconditionally?first indexWhen a lazy‑load request is in flight and the bound totalRecords changes (e.g., another user deletes rows), PrimeNG keeps the originally sent first value. If the new totalRecords is smaller than that first, the component renders an empty table until the page index is manually changed.
first and rows values from LazyLoadEvent to request data; it does not recompute first after the response arrives.first >= totalRecords after the update, the view shows no rows.first themselves or invoke the paginator’s changePage API.changePage(page: number) and an onPage event, which can be used to synchronize after data arrives.totalRecords atomically with the data array – assign both from the server response in the same callback.first >= totalRecords, reset the page index.[first] to a component property and set it to 0.paginator.changePage(0) where paginator is the Paginator reference obtained via @ViewChild.first reset inside a setTimeout(() => {...}, 0) or after change detection to avoid a flicker.To decide whether you can use paginator.changePage or must reset the [first] binding, we need to know the PrimeNG version in your package.json. If the version is ≥13, the paginator API is available; otherwise, use the [first] binding reset.
// Example component snippet (PrimeNG ≥13)
@ViewChild('paginator') paginator: Paginator;
onLazyLoad(event: LazyLoadEvent) {
this.dataService.getRows(event.first, event.rows).subscribe(resp => {
this.rows = resp.data; // update data array
this.totalRecords = resp.total; // update totalRecords atomically
if (this.first >= this.totalRecords) {
this.paginator.changePage(0); // reset to first page
}
});
}
// Example for PrimeNG <13
[first]="first"
[totalRecords]="totalRecords"
(rows)="onLazyLoad($event)"
onLazyLoad(event: LazyLoadEvent) {
this.dataService.getRows(event.first, event.rows).subscribe(resp => {
this.rows = resp.data;
this.totalRecords = resp.total;
if (this.first >= this.totalRecords) {
this.first = 0; // binding reset
}
});
}
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.