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 -
after scrolling upto 20 records -
When we scroll upto 36 record it loads all previous page data like below -
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
Showing 15 records in grid
Issue is empty rows added while scrolling from rownumber 21 to 35 after that it is working fine.
Please Help friends ...
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;
}
}