DevExtreme React - Custom Sources
To consume data from a custom source, the TreeList uses the CustomStore. This article provides details on how to configure it and on the protocol that the CustomStore adheres when communicating with the server. If the server already processes data (that is, performs filtering, sorting or grouping), notify the TreeList by assigning true to the corresponding field of the remoteOperations object.
jQuery
$(function() { $("#treeListContainer").dxTreeList({ //... remoteOperations: { filtering: true, sorting: true, // Grouping is required only when // a user can filter data using a header filter grouping: true } }); });
Angular
<dx-tree-list ... > <dxo-remote-operations [filtering]="true" [sorting]="true" [grouping]="true"> <!-- Grouping is required only when a user can filter data using a header filter --> </dxo-remote-operations> </dx-tree-list>
import { DxTreeListModule } from 'devextreme-angular'; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })
If the server does not process data yet, employ one of the following extensions by DevExtreme. They implement server-side data processing and also configure the CustomStore for you. Remember to notify the TreeList of the data processing operations that were delegated to the server.
If these extensions do not suit your needs, configure the CustomStore and implement server-side data processing following the instructions given in this article. Note that the server may leave some of the data processing operations unimplemented. In this case, make sure that the corresponding fields of the remoteOperations object are set to false.
Load Data
The CustomStore needs the load function to load data from the server. This function accepts a collection of loadOptions and passes them to the server. The server then processes data according to the loadOptions and sends it back. The following loadOptions are relevant for the TreeList:
sort: Array
Defines sorting parameters. Multiple parameters apply to the data in sequence to implement multi-level sorting. Contains objects of the following structure:{ selector: "field", desc: true/false }
filter: Array
Defines filtering parameters. Possible variants:Binary filter
[ "field", "=", 3 ]
Unary filter
[ "!", [ "field", "=", 3 ] ]
Complex filter
[ [ "field", "=", 10 ], "and", [ [ "otherField", "<", 3 ], "or", [ "otherField", ">", 11 ] ] ]
See the Filtering topic for more details.
group: Array
Defines grouping levels to be applied to the data. Each object can have the following parameters:- selector: String
The field name to group by. - desc: Boolean
Defines the selector field's descending sort order. - isExpanded: Boolean
Defines whether the group's data objects should be returned instead of grouping data. Relevant only for the last group. - groupInterval: Number or String
A numeric value groups data in ranges of the given length. A string value applies only to dates and can be one of "year", "quarter", "month", "day", "dayOfWeek", "hour", "minute" and "second". This parameter is present only when the widget sends a request for the header filter's data, and only if this data contains numbers or dates. Note that for numbers, the groupInterval option should be specified explicitly.
- selector: String
parentIds: Array
Parent IDs of rows to be loaded.
After receiving these settings, the server should apply them to data and send back an object of the following structure:
{ data: [{ key: "Group 1", items: [ ... ], // subgroups or data objects (for the last group when isExpanded = true) // can be null when isExpanded = false and there are no further groups count: 3 // count of items in this group; required only when items is null }, ... ] }
If the server has not received the group parameter, the result object should be the following:
{ data: [ ... ] // result data objects }
Here is a generalized configuration of the CustomStore for the TreeList widget.
jQuery
var treeListDataSource = new DevExpress.data.DataSource({ load: function (loadOptions) { var d = $.Deferred(); $.getJSON('http://mydomain.com/MyDataService', { sort: loadOptions.sort ? JSON.stringify(loadOptions.sort) : "", filter: loadOptions.filter ? JSON.stringify(loadOptions.filter) : "", group: loadOptions.group ? JSON.stringify(loadOptions.group) : "", parentIds: loadOptions.parentIds ? JSON.stringify(loadOptions.parentIds) : "" }).done(function (result) { // You can process the received data here d.resolve(result.data); }); return d.promise(); } }); $(function() { $("#treeListContainer").dxTreeList({ dataSource: treeListDataSource, remoteOperations: { filtering: true, sorting: true, grouping: true } }); });
Angular
import { ..., Inject } from '@angular/core'; import { Http, HttpModule, URLSearchParams } from '@angular/http'; import { DxTreeListModule } from 'devextreme-angular'; import DataSource from 'devextreme/data/data_source'; import CustomStore from 'devextreme/data/custom_store'; import 'rxjs/add/operator/toPromise'; // ... export class AppComponent { treeListDataSource: any = {}; constructor(@Inject(Http) http: Http) { this.treeListDataSource = new DataSource({ load: function (loadOptions) { let params: URLSearchParams = new URLSearchParams(); params.set("sort", loadOptions.sort ? JSON.stringify(loadOptions.sort) : ""); params.set("filter", loadOptions.filter ? JSON.stringify(loadOptions.filter) : ""); params.set("group", loadOptions.group ? JSON.stringify(loadOptions.group) : ""); params.set("parentIds", loadOptions.parentIds ? JSON.stringify(loadOptions.parentIds) : ""); return http.get('http://mydomain.com/MyDataService', { search: params }) .toPromise() .then(response => { var json = response.json(); // You can process the received data here return json.data }); } }); } } @NgModule({ imports: [ // ... DxTreeListModule, HttpModule ], // ... })
<dx-tree-list ... [dataSource]="treeListDataSource"> <dxo-remote-operations [filtering]="true" [sorting]="true" [grouping]="true"> </dxo-remote-operations> </dx-tree-list>
Add, Delete, Update Data
To allow a user to add, delete and update data in the TreeList, assign true to the corresponding field of the editing object.
jQuery
$(function(){ $("#treeListContainer").dxTreeList({ // ... editing: { allowUpdating: true, allowDeleting: true, allowAdding: true } }); });
Angular
<dx-tree-list ... > <dxo-editing [allowUpdating]="true" [allowDeleting]="true" [allowAdding]="true"> </dxo-editing> </dx-tree-list>
import { DxTreeListModule } from 'devextreme-angular'; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })
With these settings, the TreeList expects that the server can also add, update and delete data. In addition, you need to configure the CustomStore as shown below. Note that in this example, the CustomStore is not declared explicitly. Instead, CustomStore operations are implemented directly in the DataSource configuration object to shorten the example.
jQuery
var treeListDataSource = new DevExpress.data.DataSource({ // ... insert: function (values) { return $.ajax({ url: "http://mydomain.com/MyDataService/", method: "POST", data: values }) }, remove: function (key) { return $.ajax({ url: "http://mydomain.com/MyDataService/" + encodeURIComponent(key), method: "DELETE", }) }, update: function (key, values) { return $.ajax({ url: "http://mydomain.com/MyDataService/" + encodeURIComponent(key), method: "PUT", data: values }) } }); $(function() { $("#treeListContainer").dxTreeList({ dataSource: treeListDataSource, // ... }); });
Angular
import { ..., Inject } from '@angular/core'; import { Http, HttpModule, URLSearchParams } from '@angular/http'; import { DxTreeListModule } from 'devextreme-angular'; import DataSource from 'devextreme/data/data_source'; import CustomStore from 'devextreme/data/custom_store'; import 'rxjs/add/operator/toPromise'; // ... export class AppComponent { treeListDataSource: any = {}; constructor(@Inject(Http) http: Http) { this.treeListDataSource = new DataSource({ // ... insert: function (values) { return http.post('http://mydomain.com/MyDataService', values) .toPromise(); }, remove: function (key) { return http.delete('http://mydomain.com/MyDataService' + encodeURIComponent(key)) .toPromise(); }, update: function (key, values) { return http.put('http://mydomain.com/MyDataService' + encodeURIComponent(key), values) .toPromise(); } }); } } @NgModule({ imports: [ // ... DxTreeListModule, HttpModule ], // ... })
<dx-tree-list ... [dataSource]="treeListDataSource"> </dx-tree-list>
See Also
If you have technical questions, please create a support ticket in the DevExpress Support Center.