Use Custom Store

Custom Store is a Store that allows you to connect a widget to a web service with its own data accessing logic. This article describes the peculiarities of a custom store implementation related to working with the DataGrid widget.

To use a CustomStore in DataGrid for fetching data, implement the load function specifying how data must be loaded from your web service. The following code snippet shows how to do this.

By default, the data grid assumes your data service supports the following remote operations: filtering, sorting and paging. If your data service supports them, obtain grid data transformation settings from the object passed to the load function. Create the Deferred object, then get data from your web service. In this example, the getJSON function is used for this purpose. Note that data transformation settings can be passed to your web service as well. After data has been obtained successfully, resolve the Deferred object with received data and an additional object. In this additional object, set the totalCount field to the number of received records. This is needed to support paging in DataGrid.

JavaScript
var gridDataSource = {
    load: function (loadOptions) {
        var filterOptions = loadOptions.filter ? JSON.stringify(loadOptions.filter) : "";   // Getting filter settings
        var sortOptions = loadOptions.sort ? JSON.stringify(loadOptions.sort) : "";  // Getting sort settings
        var requireTotalCount = loadOptions.requireTotalCount; // You can check this parameter on the server side  
                                                               // to ensure that a number of records (totalCount) is required
        var skip = loadOptions.skip; // A number of records that should be skipped 
        var take = loadOptions.take; // A number of records that should be taken
        var d = $.Deferred();
        $.getJSON('http://mydomain.com/MyDataService', {  
            filter: filterOptions,
            sort: sortOptions,
            requireTotalCount: requireTotalCount,
            skip: skip,
            take: take
        }).done(function (result) {
            // Data processing here
            d.resolve(result.data, { totalCount: result.totalCount }); 
        });
        return d.promise();
    }
}

You may have noticed that in this code, the total number of grid records is obtained along with data using the getJSON request within the load function. If you use remote paging, you can send an individual request to get this number by specifying the totalCount function. You can also check the loadOptions | requireTotalCount option value server side to find out whether you are required to count and return the total number of records. Use the following code in addition to the code above to get the totalCount value using a separate request.

JavaScript
var gridDataSource = {
    load: function (loadOptions) {
        ...
        $.getJSON(...).done(function (data) {
            ...
            d.resolve(data); 
        });
        return d.promise();
    },
    totalCount: function(loadOptions) {
        var d = new $.Deferred();
        var filterOptions = loadOptions.filter ? JSON.stringify(loadOptions.filter) : "";  // Getting filter settings
        $.getJSON('http://mydomain.com/MyDataService', {
            filter: filterOptions
        }).done(function (totalCount) {
            ...
            d.resolve(totalCount);
        });
        return d.promise();
    }
};
NOTE
To learn how to handle CRUD operations, refer to the Data Binding article.

Refer to the DataGrid - How to implement a custom store with CRUD operations example for more information on implementing a CustomStore.

Local Operations

If your data service supports no remote operations, you can force the widget to perform all operations locally by setting the remoteOperations option to false. Moreover, when disabling the paging remote operation, you do not have to specify a total count of records for the grid as well (the totalCount function can be left without implementation). In this case, you can simply assign the URL of a web service to the dataSource option of the grid to define the remote data source.

JavaScript
var gridDataSource = 'http://mydomain.com/MyDataService';

In this case, all operations (filtering, sorting, paging, grouping and summary calculation) are performed on a client browser.

NOTE
By default, the DataGrid caches fetched data. Disabling of the remote operations or data cache may affect grid performance if the data set is large enough.

Remote Operations

If you need to process data using the remote web service, enable the remote operations. They are useful when the grid works with large amount of data, because in that case remote operations make the grid responses faster.

The following remote operations are available.

See the How to implement a data service that supports remote operations for DataGrid example for more information about implementing a data service that supports remote operations for the DataGrid widget.

Remote operations introduce a number of restrictions that are listed below.

Basic Remote Operations

By default, the basic remote operations (filtering, sorting and paging) are performed remotely server side. This requires the data service to be capable of processing data by request and the data source to be configured for requesting the processed data. Refer to the Custom Store section of this article to learn how to configure the data source to support basic remote operations.

The default mode has a number of peculiarities related to consequential conditions for loading data for all pages. They are especially significant when you have a lot of data and its reloading takes significant time. The conditions are listed below.

  1. Setting the autoExpandAll option to false at runtime.
  2. Calling the collapseAll(groupIndex) method.
  3. Using the header filter feature (assuming the header filter data source is generated automatically).
  4. Using the summaries feature.

To avoid the redundant data load in cases 1-3, enable the Remote Grouping. The Remote Summary prevents data from being reloaded in case number 4.

Advanced Remote Operations

The advanced remote operations, which are disabled by default, are grouping and summary calculation. To enable advanced remote operations along with basic remote operations, set the remoteOperations option to true.

Remote Grouping

With the DataGrid widget, you can process data for the grouping feature server side. This can allow the grid work faster with large amounts of data. To enable remote grouping, create server-side grouping implementation, configure the Custom Store according to the server's data access protocol and enable grouping's remote operation.

The server-side grouping algorithm should process the loadOptions | group field and return the JSON object to be processed in Custom Store implementation.

The loadOptions | group parameter has the following format.

JavaScript
//Numbers
group: [{ selector: "column1", groupInterval: 100, desc: false }]

//Dates
group: [
    { selector: "column1", groupInterval: "year", desc: false },
    { selector: "column1", groupInterval: "month", desc: false },
    { selector: "column1", groupInterval: "day", desc: false }
]

Once done, the request should resolve the Deferred object with the resulting data and the total count of data items.

JavaScript
var gridDataSource = {
    load: function (loadOptions) {
        var d = $.Deferred();
        $.getJSON('http://mydomain.com/MyDataService', {
            groupConfig: loadOptions.group ? JSON.stringify(loadOptions.group) : "",
            // ...
        }).done(function(result) {
            d.resolve(result.data, {
                totalCount: result.totalCount
            });
        }).fail(d.reject);
        return d.promise();
    }
}

The server should check the groupConfig variable and return the object of the following structure (the result variable).

JavaScript
{
    //...
    data: [{
        key: "Category 1", items: [/* array of items */]
    }, {
        key: "Category 2", items: [/* array of items */]
    }, ...]
}

For top hierarchy level groups, you can return the number of items in each group without the items themselves. In this case, the expansion of groups will initiate an additional request.

JavaScript
{
    //...
    data: [{
        key: "Category 1", items: null, count: 100
    }, {
        key: "Category 2", items: null, count: 200
    }, ...]
}

Remote Summary

With the DataGrid widget, you can calculate summaries server side. This can make grid work faster with large amount of data. To enable the remote summaries, you must create server-side implementation of a summaries calculation algorithm, configure the Custom Store according to the server's data access protocol and enable summary remote operation.

When remote summary is enabled, the loadOptions object has additional fields — totalSummary (the summary, calculated for the entire dataset) and groupSummary (the summary, calculated for each group when grouping is enabled). The structure of these objects is like the following.

JavaScript
[{ selector: "column1", summaryType: "sum" }, 
 { selector: "column2", summaryType: "min" },
 // ...
 { summaryType: "count" }]

The result should be placed to a summary field as shown below.

JavaScript
var gridDataSource = {
    load: function (loadOptions) {
        var d = $.Deferred();
        $.getJSON('http://mydomain.com/MyDataService', { 
            totalSummary: loadOptions.totalSummary ? JSON.stringify(loadOptions.totalSummary) : "",
            // ...
        }).done(function(result) {
            d.resolve(result.data, {
                // ...
                summary: result.summaries
            });
        }).fail(d.reject);
        return d.promise();
    }
}

The server should check the totalSummary value and return the object of the following structure (the result variable).

JavaScript
{
    //...
    summaries: [/* array of summary results */]
}

When using the group summary, the server checks the groupSummary value and returns the data object supplemented with summary values as shown below.

JavaScript
{
    //...
    data: [{
        key: "Category 1", items: null, count: 100, summary: [30, 20]
    }, {
        key: "Category 2", items: null, count: 200, summary: [100, 50]
    }, ...]
}

For details on remote grouping, refer to the Remote Grouping section.

NOTE
When the remote summaries are enabled, the widget does not support custom summary calculation.