DevExtreme jQuery/JS - Custom Data Sources
DevExtreme provides the CustomStore component to load and edit data from any data source unsupported out of the box. This article describes how to configure this component.
Client-Side Data Processing
To process data on the client, load all data from the server in the load function. You should also switch the CustomStore to the raw loadMode in all UI components except DataGrid, TreeList, PivotGrid, and Scheduler, in which this mode is already enabled:
- $(function() {
- $("#listContainer").dxList({
- dataSource: new DevExpress.data.CustomStore({
- key: "ID",
- loadMode: "raw", // omit in the DataGrid, TreeList, PivotGrid, and Scheduler
- load: function() {
- return $.getJSON("https://mydomain.com/MyDataService")
- .fail(function() { throw "Data loading error" });
- }
- })
- });
- });
Server-Side Data Processing
The communication between the CustomStore and the server is organized as follows:
- The CustomStore sends data processing settings to the server.
- The server processes data according to these settings and sends the processed dataset back.
Each setting carries information about data operation (sorting, filtering, etc.) and is present only if this operation is enabled or declared as remote. Configure remoteOperations in the DataGrid, TreeList, and PivotGridDataSource UI components or remoteFiltering in the Scheduler UI component to declare remote operations. For other UI components, use DataSource properties to enable operations.
The following example shows a CustomStore that sends data processing settings to the server. The settings are passed as the loadOptions parameter to the load function. loadOptions may contain empty settings if an operation is disabled or local. In this example, the forEach
loop filters out such settings:
- $(function() {
- var customDataSource = new DevExpress.data.CustomStore({
- key: "ID",
- load: function(loadOptions) {
- var d = $.Deferred();
- var params = {};
- [
- "filter",
- "group",
- "groupSummary",
- "parentIds",
- "requireGroupCount",
- "requireTotalCount",
- "searchExpr",
- "searchOperation",
- "searchValue",
- "select",
- "sort",
- "skip",
- "take",
- "totalSummary",
- "userData"
- ].forEach(function(i) {
- if(i in loadOptions && isNotEmpty(loadOptions[i])) {
- params[i] = JSON.stringify(loadOptions[i]);
- }
- });
- $.getJSON("https://mydomain.com/MyDataService", params)
- .done(function(response) {
- d.resolve(response.data, {
- totalCount: response.totalCount,
- summary: response.summary,
- groupCount: response.groupCount
- });
- })
- .fail(function() { throw "Data loading error" });
- return d.promise();
- },
- // Needed to process selected value(s) in the SelectBox, Lookup, Autocomplete, and DropDownBox
- // byKey: function(key) {
- // var d = new $.Deferred();
- // $.get('https://mydomain.com/MyDataService?id=' + key)
- // .done(function(result) {
- // d.resolve(result);
- // });
- // return d.promise();
- // }
- });
- $("#dataGridContainer").dxDataGrid({
- dataSource: customDataSource,
- remoteOperations: { groupPaging: true }
- });
- });
- function isNotEmpty(value) {
- return value !== undefined && value !== null && value !== "";
- }
When the server receives the data processing settings, it should apply them to the dataset and send back an object with the following structure:
- {
- data: [{
- key: "Group 1",
- items: [ ... ], // subgroups or data objects if there are no further subgroups (check group.isExpanded = true)
- // is null if group.isExpanded = false
- count: 3, // count of items in this group; required only when items = null
- summary: [30, 20, 40] // group summary results
- },
- ...
- ],
- totalCount: 200, // if requireTotalCount = true
- summary: [170, 20, 20, 1020], // total summary results
- groupCount: 35 // if requireGroupCount = true
- }
If the server did not receive the group setting, the structure should be different:
- {
- data: [ ... ], // data objects
- totalCount: 200, // if requireTotalCount = true
- summary: [170, 20, 20, 1020] // total summary results
- }
Edit Data
To implement data editing in the CustomStore, add the insert, remove, and update functions:
- $(function() {
- var customDataSource = new DevExpress.data.CustomStore({
- key: "ID",
- load: function(loadOptions) {
- // ...
- },
- insert: function(values) {
- var deferred = $.Deferred();
- $.ajax({
- url: "https://mydomain.com/MyDataService/",
- method: "POST",
- data: JSON.stringify(values)
- })
- .done(deferred.resolve)
- .fail(function(e){
- deferred.reject("Insertion failed");
- });
- return deferred.promise();
- },
- remove: function(key) {
- var deferred = $.Deferred();
- $.ajax({
- url: "https://mydomain.com/MyDataService/" + encodeURIComponent(key),
- method: "DELETE"
- })
- .done(deferred.resolve)
- .fail(function(e){
- deferred.reject("Deletion failed");
- };
- return deferred.promise();
- },
- update: function(key, values) {
- var deferred = $.Deferred();
- $.ajax({
- url: "https://mydomain.com/MyDataService/" + encodeURIComponent(key),
- method: "PUT",
- data: JSON.stringify(values)
- })
- .done(deferred.resolve)
- .fail(function(e){
- deferred.reject("Update failed");
- };
- return deferred.promise();
- }
- });
- // ...
- });
If you have technical questions, please create a support ticket in the DevExpress Support Center.