DevExtreme jQuery - Enhance Performance on Large Datasets
We recommend enabling remoteOperations and delegating data processing operations to the server as described in the Custom Sources topic if the DataGrid is using a large dataset. Additionally, you can make the following tweaks to enhance the DataGrid's performance.
Deferred Selection
Use the deferred mode to increase the DataGrid's performance when selecting multiple rows at once. In this mode, only the API - for example, the getSelectedRowsData() or getSelectedRowKeys() method - can request the DataGrid data. Assign true to the selection.deferred option to use deferred selection.
jQuery
$(function(){ $("#dataGridContainer").dxDataGrid({ // ... dataSource: { store: { type: "odata", url: "https://js.devexpress.com/Demos/DevAV/odata/Products", key: "Product_ID" } }, selection: { mode: 'multiple', allowSelectAll: true, deferred: true } }); });
Angular
<dx-data-grid [dataSource]="dataSource"> <dxo-selection mode="multiple" [allowSelectAll]="true" [deferred]="true"> </dxo-selection> </dx-data-grid>
import { DxDataGridModule } from 'devextreme-angular'; import 'devextreme/data/odata/store'; // ... export class AppComponent { dataSource = { store: { type: "odata", url: "https://js.devexpress.com/Demos/DevAV/odata/Products", key: "Product_ID" } } } @NgModule({ imports: [ // ... DxDataGridModule ], // ... })
The following tasks require using different API in the deferred mode comparing with usual (instant) one:
Setting initial selection
The deferred mode requires using the selectionFilter instead of the selectedRowKeys option to set the initially selected rows. Pass a filter expression to define records that must be selected.
jQuery
JavaScript$(function () { $("#dataGridContainer").dxDataGrid({ // ... selectionFilter: ["Task_Status", "=", "Completed"] }); });
Angular
HTMLTypeScript<dx-data-grid ... [selectionFilter]="['Task_Status', '=', 'Completed']"> </dx-data-grid>
import { DxDataGridModule } from 'devextreme-angular'; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxDataGridModule ], // ... })
The DataGrid changes the selectionFilter option's value internally each time a user selects a row. You can use the following code to obtain this option's current value and send it to the server:
jQuery
JavaScriptfunction sendSelectedRows() { var selectionFilter = dataGridInstance.option("selectionFilter"); $.ajax({ method: "POST", url: "url/to/data/processing/method", data: { filter: (selectionFilter ? JSON.stringify(selectionFilter) : null) } }); }
Angular
TypeScriptimport { ..., ViewChild } from '@angular/core'; import { Http, HttpModule } from '@angular/http'; import { DxDataGridModule, DxDataGridComponent } from 'devextreme-angular'; // ... export class AppComponent { @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent; constructor(private http: Http) { } sendSelectedRows() { var selectionFilter = this.dataGrid.instance.option("selectionFilter"); this.http .post('url/to/data/processing/method', "filter: " + (selectionFilter ? JSON.stringify(selectionFilter) : null) ) .subscribe(); } } @NgModule({ imports: [ // ... DxDataGridModule, HttpModule ], // ... })
Checking whether a row is selected
Use the isRowSelected(data) method to find out whether a specific row is selected.
Getting the selected rows' data
In the deferred mode, the getSelectedRowsData() and getSelectedRowKeys() methods return a native Promise or a jQuery.Promise when you use jQuery. Get the selected data within the callback function that resolves this object.
See Also
- key in ArrayStore | CustomStore | LocalStore | ODataStore
Lookup Optimization
As a rule, a lookup column contains IDs from a main data source field but displays human-readable values from its own data source. When the DataGrid first launches, it loads data from both data sources which causes performance to decrease.
You can send the human-readable values from the server as a part of the main data source alongside the IDs (like in this example) to optimize the lookup column. In this case, use the column's calculateDisplayValue option to specify which field provides the human-readable values. With this optimization, the lookup data source is not loaded until a user starts editing the lookup column.
jQuery
$(function () { $("#dataGridContainer").dxDataGrid({ //... columns: [{ caption: "Customer", // "CustomerName" provides human-readable values calculateDisplayValue: "CustomerName", dataField: "CustomerID", lookup: { valueExpr: "CustomerID", displayExpr: "ContactName", dataSource: { store: { // ... key: "CustomerID" } } } }, // ... ] }); });
Angular
<dx-data-grid ...> <dxi-column caption="Customer" dataField="CustomerID" calculateDisplayValue="CustomerName"> <!-- "CustomerName" provides human-readable values --> <dxo-lookup [dataSource]="dataSource" displayExpr="ContactName" valueExpr="CustomerID"> </dxo-lookup> </dxi-column> </dx-data-grid>
import { DxDataGridModule } from 'devextreme-angular'; import 'devextreme/data/array_store'; // or // import 'devextreme/data/odata/store'; // import 'devextreme/data/custom_store'; export class AppComponent { dataSource: any; constructor() { this.dataSource = { store: { // ... key: "CustomerID" } } } } @NgModule({ imports: [ // ... DxDataGridModule ], // ... })
See Also
Remote Group Paging
Remote group paging is a feature that allows loading groups from a remote source in portions. With it, the DataGrid transmits significantly less data, thus speeding up grouping. As a downside, requests become more frequent, because the DataGrid sends several of them each time a user expands a group or sorts/filters data.
When using remote group paging, the following restrictions apply:
- The server should perform filtering, paging, grouping, and sorting;
- All groups should be collapsed initially by setting the grouping.autoExpandAll option to false;
- The expandAll(groupIndex) method should not be called. Otherwise, the widget ignores remote group paging.
Set the remoteOperations.groupPaging option to true to enable remote group paging. Note that with this setting, all other data processing operations (filtering, sorting, grouping, paging and summary calculation) also become remote.
jQuery
$(function() { $("#dataGridContainer").dxDataGrid({ //... remoteOperations: { groupPaging: true } }); });
Angular
<dx-data-grid ... > <dxo-remote-operations [groupPaging]="true"></dxo-remote-operations> </dx-data-grid>
import { DxDataGridModule } from 'devextreme-angular'; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxDataGridModule ], // ... })
Now, the DataGrid requires server-implemented group paging. Use the following ASP.NET and PHP server extensions to implement group paging and other data processing operations:
For servers built on other technologies, implement all data processing operations by yourself and configure data access on the client side using the CustomStore as shown in the Custom Sources - Load Data topic. Mind that the result object described in there should also contain the groupCount field specifying the count of top-level groups, and the items field of each data object should be equal to null.
{ data: [{ key: "Group 1", count: 3, items: null, summary: [30, 20, 40] }, ... ], totalCount: 200, groupCount: 35, // this field added; count of top-level groups returned if requireGroupCount is true summary: [170, 20, 20, 1020] }
The groupCount should be returned only if the requireGroupCount parameter in the loadOptions is true. The following code is amended to query data from a server that supports remote group paging:
jQuery
var gridDataSource = new DevExpress.data.DataSource({ load: function (loadOptions) { var d = $.Deferred(); $.getJSON('http://mydomain.com/MyDataService', { skip: loadOptions.skip, take: loadOptions.take, sort: loadOptions.sort ? JSON.stringify(loadOptions.sort) : "", filter: loadOptions.filter ? JSON.stringify(loadOptions.filter) : "", requireTotalCount: loadOptions.requireTotalCount, totalSummary: loadOptions.totalSummary ? JSON.stringify(loadOptions.totalSummary) : "", group: loadOptions.group ? JSON.stringify(loadOptions.group) : "", groupSummary: loadOptions.groupSummary ? JSON.stringify(loadOptions.groupSummary) : "", requireGroupCount: loadOptions.requireGroupCount // added }).done(function (result) { d.resolve(result.data, { totalCount: result.totalCount, summary: result.summary, groupCount: result.groupCount // added }); }); return d.promise(); } }); $(function() { $("#datadataGridContainer").dxDataGrid({ dataSource: gridDataSource, remoteOperations: { groupPaging: true } }); });
Angular
import { ..., Inject } from '@angular/core'; import { Http, HttpModule, URLSearchParams } from '@angular/http'; import DataSource from 'devextreme/data/data_source'; import CustomStore from 'devextreme/data/custom_store'; import 'rxjs/add/operator/toPromise'; // ... export class AppComponent { gridDataSource: any = {}; constructor(@Inject(Http) http: Http) { this.gridDataSource = new DataSource({ load: function (loadOptions) { let params: URLSearchParams = new URLSearchParams(); params.set("skip", loadOptions.skip); params.set("take", loadOptions.take); params.set("sort", loadOptions.sort ? JSON.stringify(loadOptions.sort) : ""); params.set("filter", loadOptions.filter ? JSON.stringify(loadOptions.filter) : ""); params.set("requireTotalCount", loadOptions.requireTotalCount); params.set("totalSummary", loadOptions.totalSummary ? JSON.stringify(loadOptions.totalSummary) : ""); params.set("group", loadOptions.group ? JSON.stringify(loadOptions.group) : ""); params.set("groupSummary", loadOptions.groupSummary ? JSON.stringify(loadOptions.groupSummary) : ""); params.set("requireGroupCount", loadOptions.requireGroupCount); // added return http.get('http://mydomain.com/MyDataService', { search: params }) .toPromise() .then(response => { var json = response.json(); // You can process the received data here return { data: json.data, totalCount: json.totalCount, summary: json.summary, groupCount: result.groupCount // added } }); } }); } } @NgModule({ imports: [ // ... DxDataGridModule, HttpModule ], // ... })
<dx-data-grid ... [dataSource]="gridDataSource" [remoteOperations]="{groupPaging: true}"> </dx-data-grid>
See Also
If you have technical questions, please create a support ticket in the DevExpress Support Center.