Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PrimeNG TurboTable - strange virtual scroll behaviour - keeps doubling event.rows

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:

  1. event.first always stays 0
  2. event.rows keeps doubling to very high values

I 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!

like image 457
Botond Béres Avatar asked Apr 10 '19 08:04

Botond Béres


2 Answers

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.

like image 164
RV. Avatar answered Oct 03 '22 12:10

RV.


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;
}
like image 24
Botond Béres Avatar answered Oct 03 '22 10:10

Botond Béres