我们需要使用虚拟滚动来实现kendo网格,但我们需要从服务器获取数百万个数据,因此我们无法将所有数据都放入同一个请求中。 我关注这些文章(http://www.telerik.com/kendo-angular-ui/components/grid/configuration/#toc-scroll-modes,http://www.telerik.com/kendo-angular-ui/components/grid/data-binding/),但分页的虚拟滚动无效。
我的代码:
MSA-grid.component.ts
import { Component, OnInit, ViewChild, ElementRef, Input } from '@angular/core';
import { products } from './products';
import { MsaGridCol } from './MsaGridCol';
import { MsaGridService } from './services/msa-grid.service';
import { Observable, BehaviorSubject } from 'rxjs/Rx';
import * as $ from 'jquery';
import {
GridDataResult,
PageChangeEvent
} from '@progress/kendo-angular-grid';
import {
} from '@progress/kendo-data-query';
@Component({
selector: 'msa-grid',
templateUrl: './msa-grid.component.html',
styleUrls: ['./msa-grid.component.scss']
})
export class MsaGridComponent implements OnInit {
//The data to view
@Input() private gridData: Array<any> | Observable<GridDataResult>;
//The selection option
@Input() private selectionType: string = null;
//The table columns to show
@Input() private gridCols: Array<MsaGridCol> = new Array<MsaGridCol>();
//If the data has to be get from remote or not
@Input() private remote: boolean = true;
//If true divide data in pages with paginator
@Input() private pageable: boolean = false;
//Scrolling: if scrollable = 'virtual' pageable go to false
@Input() private scrollable: string = null;
//Set the grid height
@Input() private height: number = null;
//Page Size: THe page size if pageable or virtual-scrolling are enable
@Input() private pageSize: number = 12;
//Service Url: Your service data url
@Input() private serviceUrl: string = "";
//The records to skip
private skip: number = 0;
//The selected items
private selectedItems: Array<any> = new Array<any>();
//The table template
@ViewChild("msaGridTemplate") msaGridTemplate: ElementRef;
constructor(private msaGridService: MsaGridService) {
}
ngOnInit() {
if (this.scrollable == 'virtual') {
this.pageable = false;
}
if (this.remote) {
this.gridData = this.msaGridService;
this.pageChange({ skip: this.skip, take: this.pageSize });
}
}
//Function that select (or deselect) the clicked record into the table
selectItem(event, product) {
if (event.currentTarget.checked) {
if (this.selectionType == 'single') {
$(this.msaGridTemplate.nativeElement).find(".k-state-selected").find(".tableSelectionCheckbox").prop("checked", false);
$(this.msaGridTemplate.nativeElement).find(".k-state-selected").removeClass("k-state-selected");
this.selectedItems = new Array<any>();
}
this.selectedItems.push(product);
$(event.currentTarget).closest("tr").addClass("k-state-selected");
} else {
this.selectedItems = this.selectedItems.filter(el => !(JSON.stringify(el) == JSON.stringify(product)));
$(event.currentTarget).closest("tr").removeClass("k-state-selected");
}
console.log("SELECTED ITEMS", this.selectedItems.map((el) => el.ProductID));
}
//Function that select (or deselect) all the records into the table
selectAllItem(event) {
if (event.currentTarget.checked) {
$(this.msaGridTemplate.nativeElement).find(".k-grid-content tr").each((index, el) => {
if (!$(el).hasClass("k-state-selected")) {
$(el).addClass("k-state-selected")
$(el).find(".tableSelectionCheckbox").prop('checked', true);
}
this.selectedItems = JSON.parse(JSON.stringify(this.gridData));
});
} else {
$(this.msaGridTemplate.nativeElement).find(".k-grid-content tr").each((index, el) => {
if ($(el).hasClass("k-state-selected")) {
$(el).removeClass("k-state-selected");
$(el).find(".tableSelectionCheckbox").prop('checked', false);
}
this.selectedItems = new Array<any>();
});
}
}
//When a change page is detected
protected pageChange(event: PageChangeEvent): void {
if (this.remote) {
this.skip = event.skip;
this.msaGridService.query({ skip: this.skip, take: this.pageSize });
}
}
}
MSA-grid.component.html
<div #msaGridTemplate>
<kendo-grid [data]="gridData | async"
[height]="370"
[selectable]="false"
[pageable]="false"
[scrollable]="'virtual'"
[skip]="skip"
[pageSize]="pageSize"
(pageChange)="pageChange($event)">
<kendo-grid-column field="SelectRows" title="ID" width="40" *ngIf="selectionType">
<template kendoGridHeaderTemplate >
<span><input type="checkbox" *ngIf="selectionType == 'multiple'" (change)="selectAllItem($event)" /></span>
</template>
<template kendoGridCellTemplate let-dataItem *ngIf="selectionType">
<input class="tableSelectionCheckbox" type="checkbox" (change)="selectItem($event, dataItem)" />
</template>
</kendo-grid-column>
<kendo-grid-column *ngFor="let col of gridCols" field="{{col.field}}" title="{{col.title}}" width="{{col.width}}">
<template kendoGridHeaderTemplate *ngIf="col.headerTemplate">
<msa-template-wrapper-component [componentType]="col.headerTemplate" [dataItem]="dataItem"></msa-template-wrapper-component>
</template>
<template kendoGridCellTemplate let-dataItem *ngIf="col.cellTemplate">
<msa-template-wrapper-component [componentType]="col.cellTemplate" [dataItem]="dataItem[col.field]"></msa-template-wrapper-component>
</template>
</kendo-grid-column>
</kendo-grid>
</div>
MSA-gris.service.ts
import { Component, ViewChild, Input, OnInit, Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable, BehaviorSubject } from 'rxjs/Rx';
import {
GridComponent,
GridDataResult,
DataStateChangeEvent
} from '@progress/kendo-angular-grid';
import {
toODataString
} from '@progress/kendo-data-query';
@Injectable()
export class MsaGridService extends BehaviorSubject<GridDataResult>{
private BASE_URL: string = 'http://services.odata.org/V4/Northwind/Northwind.svc/';
private tableName: string = "Customers";
constructor(private http: Http) {
super(null);
}
query(state): void {
this.fetch(this.tableName, state)
.subscribe(x => super.next(x));
}
fetch(tableName: string, state: any): Observable<GridDataResult> {
const queryStr = `${toODataString(state)}&$count=true`;
return this.http
.get(`${this.BASE_URL}${tableName}?${queryStr}`)
.map(response => response.json())
.map(response => (<GridDataResult>{
data: response.value,
total: parseInt(response["@odata.count"], 10)
}));
}
}
答案 0 :(得分:0)
虚拟滚动和分页无法正常工作。例如;如果要在索引0到10之间的网格上呈现数据,则应至少从服务器中获取30个数据。因为您不希望每次滚动操作都从服务器获取数据。 (跳过:1接受:11,跳过:2接受:12,跳过:3接受:13 ...)
那我们该怎么办?我们需要以30个块的形式获取数据,但应在网格中呈现10行。我们的页面大小为10,但实际页面大小应为30。(这里的数字30是我们页面大小的3倍。没关系。您可以使用4倍,5倍或您想要的大小。)再一次这个场景。