I've implemented a custom Grid component that uses PrimeNG TurboTable and NgRx and I've added the virtual scroll feature to it using the built-in TurboTable virtual scroll. It is also lazy loading, with onLazyLoad
handler. However, I get this strange behaviour when onLazyLoad
is called as I am scrolling through the grid results.
onLazyLoad called with event.first=0 and event.rows=40
onLazyLoad called with event.first=0 and event.rows=80
onLazyLoad called with event.first=0 and event.rows=160
onLazyLoad called with event.first=0 and event.rows=320
onLazyLoad called with event.first=0 and event.rows=640
onLazyLoad called with event.first=0 and event.rows=1280
So there are 2 problems:
event.first
always stays 0 event.rows
keeps doubling to very
high valuesI thought that it's a bug in PrimeNG but when I've tried to reproduce it with a simple StackBlitz, there it is behaving correctly. https://stackblitz.com/edit/github-primeng-virtualscroll-issue
I see this on StackBlitz:
loadDataOnScroll is called with event.first=0 and event.rows=40
loadDataOnScroll is called with event.first=20 and event.rows=40
loadDataOnScroll is called with event.first=40 and event.rows=40
loadDataOnScroll is called with event.first=80 and event.rows=40
loadDataOnScroll is called with event.first=120 and event.rows=40
So event.rows
stays constant as it is supposed to and event.first
increases normally.
Looks like something is triggering this from the way I use the TurboTable, but I don't know what. What could be the issue? Here is the relevant code from my grid component:
The lazy load handler:
onLazyLoad(event: LazyLoadEvent) {
// TODO - In this StackBlitz it behaves correctly
// https://stackblitz.com/edit/github-primeng-virtualscroll-issue
console.log(
`onLazyLoad called with event.first=${event.first} and event.rows=${
event.rows
}`
);
// TODO - This state should be handled by NgRx as well.
this.loading = true;
this.filters = {};
const hasPagination = this.settings.features.Pagination;
// TODO - Tweak the behavior of virtual scroll skipCount/maxResultCount
// based on testing results.
// The default behavior is a bit strange, skipCount is always 0
// and maxResultCount keeps getting doubled.
let pageSize = event.rows ? event.rows : GridConfig.PageSize;
this.filters.maxResultCount = pageSize;
this.filters.skipCount = event.first ? event.first : 0;
this.filters.ignorePagination = !hasPagination;
if (event.sortOrder && event.sortField) {
const sortingDirection = event.sortOrder > 0 ? 'ASC' : 'DESC';
this.filters.sorting = event.sortField + ' ' + sortingDirection;
}
if (event.globalFilter) {
this.filters.filter = event.globalFilter;
}
if (event.filters) {
this.filters.columnFilters = this.buildColumnFilters(event.filters);
}
this.filters.parentFilters = this.parentFilters; // this works only with client-side caching & filtering
if (this.settings.features.ClientSideCaching) {
// Load only once
this.gridLoaded().subscribe(loaded => {
if (loaded) {
this.store.dispatch(
new this.settings.stateActions.FilterClientSide(
this.filters
)
);
}
});
} else {
this.store.dispatch(
new this.settings.stateActions.Read(this.filters)
);
}
}
The parameters I pass in the template:
<p-table
#dataTable
[value]="(data$ | async)?.items"
[loading]="loading"
[lazy]="true"
[virtualScroll]="!settings.features.Pagination"
[virtualRowHeight]="35"
[scrollable]="!settings.features.Pagination"
(onLazyLoad)="onLazyLoad($event)"
[autoLayout]="true"
[columns]="selectedColumns"
[paginator]="settings.features.Pagination"
scrollHeight="400px"
[resizableColumns]="true"
[rowsPerPageOptions]="[10, 20, 30]"
[totalRecords]="(data$ | async)?.totalCount"
[rows]="(this.settings.states.Search | async)?.maxResultCount"
[stateStorage]="this.settings.persistence?.stateStorage"
[stateKey]="this.settings.persistence?.stateKey"
[(selection)]="selectedRows"
[selectionMode]="this.settings.rowSelection?.selectionMode || null"
(onRowSelect)="onRowSelect($event)"
[dataKey]="this.settings.rowSelection?.dataKey || null"
>
Any help or ideas would be much appreciated! Thanks!
This could be because in the https://stackblitz.com/edit/github-primeng-virtualscroll-issue you have a hard-coded total record count parameter to <p-table>
.
Where as in your actual implementation you may be setting to something smaller than your dataset size or 0 (Looks like you have an observable there. Check on what does it evaluate to. Try setting some large number greater than your dataset to see if this theory is correct).
Check on what does [totalRecords]="(data$ | async)?.totalCount"
parameter evaluates to you in your implementation for <p-table>
.
Hopefully this will fix it.
The problem happened because event.rows
is persisted in the NgRx store and I was reusing it when building the filters and every time onLazyLoad
gets called it would get doubled.
Here I initialize rows
with the NgRx store value:
[rows]="(this.settings.states.Search | async)?.maxResultCount"
Then inside onLazyLoad
I was using event.rows
:
let pageSize = event.rows ? event.rows : GridConfig.PageSize;
this.filters.maxResultCount = pageSize;
PrimeNG doubles event.rows
in their code for virtual scroll and it gets persisted into the NgRx store when I call FilterClientSide
action. Then the template gets that new value and on a subsequent onLazyLoad
it gets doubled again.
The solution that worked for me was to just set a constant for this:
if (this.settings.features.VirtualScroll) {
pageSize = GridConfig.PageSize * 2;
} else {
pageSize = event.rows ? event.rows : 10;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With