Search code examples
angularjqxgrid

jqxGrid Virtual scrolling empty space OR Empty rows inserted


I am implementing virtual scrolling in Angular 5 with ASP.NET Zero Project. I have seen some empty spaces after some scrolling (lets say startIndex=6 and endIndex=25). Some rows are not displayed even if grid has data to show. This issue is happening till startIndex=19 and endIndex=38 (where number of missing rows increases) but once scrolling reaches till startIndex=20 and endIndex=398, it again start working well.

Initially grid views is look like - enter image description here

after scrolling upto 20 records -

enter image description here

enter image description here

When we scroll upto 36 record it loads all previous page data like below -

enter image description here

My Code is as below –

<jqxGrid #customersGrid [width]="'100%'" [height]="450" [source]="dataAdapter" [columns]="columns" [virtualmode]="true" [rendergridrows]="rendergridrows" (onRowselect)="rowSelect($event)" [filterable]="true" (onFilter)="filterCustomers()" [autoshowfiltericon]="true" [updatefilterconditions]="updatefilterconditions" [sortable]="true" (onSort)="sortCustomers($event)" [altrows]="true" [selectionmode]="'singlerow'"></jqxGrid>

component.ts code –

import { jqxGridComponent } from 'jqwidgets-framework/jqwidgets-ts/angular_jqxgrid';
import {
  CustomerServiceProxy,
  CustomerListDto,
  EntityDtoOfInt64,
  FilterRule
} from 'shared/service-proxies/service-proxies';
@Component({
  templateUrl: './customers.component.html',
  styleUrls: ['./customers.component.less'],
  animations: [appModuleAnimation()]
})
export class CustomersComponent extends AppComponentBase implements OnInit {
 @ViewChild('customersGrid') customersGrid: jqxGridComponent;

 customers: Array<CustomerListDto> = [];
  isGridDataPrepared = false;
  rendergridrows: any;
  source: any;
  dataAdapter: any;

  columns: any[] = [
    {
      pinned: true,
      exportable: false,
      sortable: false,
      menu: false,
      text: '',
      columntype: 'number',
      cellclassname: 'jqx-widget-header',
      cellsrenderer: this.numberRenderer,
      width: '4%'
    },
    {
      text: this.l('CustomerNumber'),
      datafield: 'customerNumber',
      cellsalign: 'center',
      width: '10%'
    },
    {
      text: this.l('CustomerName'),
      datafield: 'lastNameFirstCo'
    },
    {
      text: this.l('CustomerAddress'),
      datafield: 'address'
    },
    {
      text: this.l('CustomerAddress2'),
      datafield: 'address2'
    },
    {
      text: this.l('CustomerCity'),
      datafield: 'city'
    },
    {
      text: this.l('CustomerState'),
      datafield: 'state',
      cellsalign: 'center',
      width: '8%'
    },
    {
      text: this.l('CustomerZip'),
      datafield: 'zip',
      cellsalign: 'center',
      width: '10%'
    },
    {
      text: this.l('Active'),
      datafield: 'isActive',
      cellsalign: 'center',
      filtertype: 'checkedlist',
      filteritems: [{ value: true, label: 'YES' }, { value: false, label: 'NO' }],
      cellsrenderer: this.boolRenderer,
      width: '8%'
    }
  ];

  filters: {
    sorting: string;
    params: { startindex: number; endindex: number };
  } = {
      sorting: 'lastNameFirstCo asc',
      params: { startindex: 0, endindex: this.pageSize }
    };

    constructor(
    injector: Injector,
    private customerService: CustomerServiceProxy
  ) {
    super(injector);
  }


  ngOnInit(): void {
    this.obj = new FilterRule();
    this.initGrid();
    this.getCustomers();
  }

  initGrid() {
    this.customers = [];
    this.source = {
      datatype: 'json',
      datafields: [
        { name: '', type: 'number' },
        { name: 'customerNumber', type: 'string' },
        { name: 'lastNameFirstCo', type: 'string' },
        { name: 'address', type: 'string' },
        { name: 'address2', type: 'string' },
        { name: 'city', type: 'string' },
        { name: 'state', type: 'string' },
        { name: 'zip', type: 'number' },
        { name: 'isActive', type: 'boolean' }
      ],
      localdata: {},
      sortcolumn: 'lastNameFirstCo',
      sortdirection: 'asc',
      totalrecords: 10000000
    };
    this.dataAdapter = new jqx.dataAdapter(this.source);
  }


  getCustomers(from, isFromInit: boolean = false) {
    this.customerService
      .getCustomers(
        '',
        this.obj.condition,
        this.obj.field,
        this.obj.id,
        this.obj.input,
        this.obj.operator,
        this.obj.rules,
        this.obj.type,
        this.obj.value,
        this.filters.sorting,
        this.pageSize,
        this.filters.params.startindex
      )
      .debounceTime(500)
      .subscribe(result => {
        if (result.totalCount >= 0) {
          this.customers = result.items;
          // this.customers.slice(0, this.filters.params.startindex);
          // this.customers = this.customers.concat(result.items);
          this.source.totalrecords = result.totalCount;
          // this.customersGrid.updatebounddata('sort');
        } else {
          this.customers = [];
          this.source.totalrecords = 0;
        }


        if (isFromInit) {
          let lastIndex = this.pageSize;
           // load virtual data.
          this.rendergridrows = (params: any): any[] => {
           this.filters.params = params;

            this.customers = _.takeWhile(
              this.customers,
              customer => customer.id
            );

            return this.customers;
           };


          this.isGridDataPrepared = true;
          }
      });
  }

 }

Note – 1. I used PageSize = 20

  1. Showing 15 records in grid

  2. Issue is empty rows added while scrolling from rownumber 21 to 35 after that it is working fine.

Please Help friends ...


Solution

  • To solve the above issue we have to maintain an Array object locally and insert the newly received data in our local array.

    For example -

    @Component({
      templateUrl: "./employee.component.html",
      styleUrls: ["./employee.component.less"],
      animations: [appModuleAnimation()]
    })
    
    export class EmployeesComponent extends AppComponentBase implements OnInit {
     @ViewChild("employeesGrid") employeesGrid: jqxGridComponent;
    employees: Array<EmployeeListDto> = [];
    
    rendergridrows = (params: any): any[] => {
    //get data from server then append in employees array
    return this.employees;
    }
    
    }