DevExtreme jQuery/JS - Custom Sources
Access to a custom data source is configured using the CustomStore component. DevExtreme provides ASP.NET and PHP extensions to configure the CustomStore and implement server-side data processing. You can also use the third-party extension for MongoDB.
You need to configure the CustomStore in detail for accessing a server built on another technology. Data in this situation can be processed on the client or server. In the former case, switch the CustomStore to the raw mode and load all data from the server in the load function as shown in the following example:
jQuery
$(function() { $("#listContainer").dxList({ dataSource: new DevExpress.data.DataSource({ store: new DevExpress.data.CustomStore({ key: "ID", loadMode: "raw", load: function () { return $.getJSON('https://mydomain.com/MyDataService'); } }) }) }); });
Angular
import { ..., Inject } from "@angular/core"; import { HttpClient, HttpClientModule } from "@angular/common/http"; import { DxListModule } 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 { listDataSource: any = {}; constructor(@Inject(HttpClient) httpClient: HttpClient) { this.listDataSource = new DataSource({ store: new CustomStore({ key: "ID", loadMode: "raw", load: () => { return httpClient.get('http://mydomain.com/MyDataService') .toPromise(); } }) }); } } @NgModule({ imports: [ // ... DxListModule, HttpClientModule ], // ... })
<dx-list ... [dataSource]="listDataSource"> </dx-list>
Vue
<template> <DxList ... :data-source="dataSource" /> </template> <script> import { DxList } from "devextreme-vue/list"; import CustomStore from "devextreme/data/custom_store"; import DataSource from "devextreme/data/data_source"; import 'whatwg-fetch'; // ... function handleErrors(response) { if (!response.ok) throw Error(response.statusText); return response; } const listDataSource = new DataSource({ store: new CustomStore({ key: "ID", loadMode: "raw", load: () => { return fetch("https://mydomain.com/MyDataService") .then(handleErrors); } }) }); export default { // ... data() { return { dataSource: listDataSource }; }, components: { // ... DxList } } </script>
React
import React from "react"; import List from "devextreme-react/list"; import CustomStore from "devextreme/data/custom_store"; import DataSource from "devextreme/data/data_source"; import 'whatwg-fetch'; // ... function handleErrors(response) { if (!response.ok) throw Error(response.statusText); return response; } const listDataSource = new DataSource({ store: new CustomStore({ key: "ID", loadMode: "raw", load: () => { return fetch("https://mydomain.com/MyDataService") .then(handleErrors); } }) }); class App extends React.Component { render() { return ( <List ... dataSource={listDataSource}> </List> ); } } export default App;
In the latter case, use the CustomStore's load function to send data processing settings to the server. These settings are passed as a parameter to the load function and depend on the operations (paging, filtering, sorting, etc.) that you have enabled in the DataSource. The following settings are relevant for the List:
Paging settings: take, skip, requireTotalCount
Present if paginate is true and pageSize is set in the DataSource. The requireTotalCount setting appears when the List's selectAllMode is "allPages".Sorting settings: sort
Present if the DataSource's sort option is set.Filtering settings: filter
Present if the DataSource's filter option is set or searching is enabled in the widget.Searching settings: searchExpr, searchOperation, and searchValue
Present if corresponding options are set in the DataSource.Grouping settings: group
Present if the DataSource's group option is set.
After receiving these settings, the server should apply them to data and send back an object with the following structure:
{ data: [{ key: "Group 1", items: [ ... ] // result data objects }, ... ], totalCount: 100 }
If the server has not received the group parameter, the resulting object should be as follows:
{ data: [ ... ], // result data objects totalCount: 100 }
If the List allows the user to delete items, the CustomStore must implement the remove operation as well. Below is a generalized configuration of the CustomStore for the List widget.
jQuery
$(function() { $("#listContainer").dxList({ dataSource: new DevExpress.data.DataSource({ key: "ID", load: function(loadOptions) { var d = $.Deferred(), params = {}; [ "skip", "take", "sort", "filter", "searchExpr", "searchOperation", "searchValue", "group", "requireTotalCount" ].forEach(function(i) { if(i in loadOptions && isNotEmpty(loadOptions[i])) params[i] = JSON.stringify(loadOptions[i]); }); $.getJSON("http://mydomain.com/MyDataService", params) .done(function(result) { // Here, you can perform operations unsupported by the server d.resolve(result.data, { totalCount: result.totalCount }); }); return d.promise(); }, remove: function(key) { return $.ajax({ url: "http://mydomain.com/MyDataService/" + encodeURIComponent(key), method: "DELETE" }); } }) }); }); function isNotEmpty(value) { return value !== undefined && value !== null && value !== ""; }
Angular
import { ..., Inject } from "@angular/core"; import { HttpClient, HttpClientModule, HttpParams } from "@angular/common/http"; import { DxListModule } 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 { listDataSource: any = {}; constructor(@Inject(HttpClient) httpClient: HttpClient) { function isNotEmpty(value: any): boolean { return value !== undefined && value !== null && value !== ""; } this.listDataSource = new DataSource({ store: new CustomStore({ key: "ID", load: (loadOptions) => { let params: HttpParams = new HttpParams(); [ "skip", "take", "sort", "filter", "searchExpr", "searchOperation", "searchValue", "group", "requireTotalCount" ].forEach(function(i) { if(i in loadOptions && isNotEmpty(loadOptions[i])) params = params.set(i, JSON.stringify(loadOptions[i])); }); return httpClient.get("http://mydomain.com/MyDataService", { params: params }) .toPromise() .then(result => { // Here, you can perform operations unsupported by the server return { data: result.data, totalCount: result.totalCount }; }); }, remove: function(key) { return httpClient.delete('http://mydomain.com/MyDataService' + encodeURIComponent(key)) .toPromise(); } }) }); } } @NgModule({ imports: [ // ... DxListModule, HttpClientModule ], // ... })
<dx-list [dataSource]="listDataSource"> </dx-list>
Vue
<template> <DxList ... :data-source="dataSource" /> </template> <script> import DxList from "devextreme-vue/list"; import CustomStore from "devextreme/data/custom_store"; import 'whatwg-fetch'; // ... function isNotEmpty(value) { return value !== undefined && value !== null && value !== ""; } function handleErrors(response) { if (!response.ok) throw Error(response.statusText); return response; } const listDataSource = { store: new CustomStore({ key: "ID", load: (loadOptions) => { let params = "?"; [ "skip", "take", "sort", "filter", "searchExpr", "searchOperation", "searchValue", "group", "requireTotalCount" ].forEach(function(i) { if(i in loadOptions && isNotEmpty(loadOptions[i])) params += `${i}=${JSON.stringify(loadOptions[i])}&`; }); params = params.slice(0, -1); return fetch(`https://mydomain.com/MyDataService${params}`) .then(handleErrors) .then(response => response.json()) .then((result) => { return { data: result.data, totalCount: result.totalCount } }); }, remove: (key) => { return fetch(`https://mydomain.com/MyDataService/${encodeURIComponent(key)}`, { method: "DELETE" }).then(handleErrors); } }) } export default { // ... data() { return { dataSource: listDataSource }; }, components: { // ... DxList } } </script>
React
import React from "react"; import List from "devextreme-react/list"; import CustomStore from "devextreme/data/custom_store"; import 'whatwg-fetch'; // ... function isNotEmpty(value) { return value !== undefined && value !== null && value !== ""; } function handleErrors(response) { if (!response.ok) throw Error(response.statusText); return response; } const listDataSource = { store: new CustomStore({ key: "ID", load: (loadOptions) => { let params = "?"; [ "skip", "take", "sort", "filter", "searchExpr", "searchOperation", "searchValue", "group", "requireTotalCount" ].forEach(function(i) { if(i in loadOptions && isNotEmpty(loadOptions[i])) params += `${i}=${JSON.stringify(loadOptions[i])}&`; }); params = params.slice(0, -1); return fetch(`https://mydomain.com/MyDataService${params}`) .then(handleErrors) .then(response => response.json()) .then((result) => { return { data: result.data, totalCount: result.totalCount } }); }, remove: (key) => { return fetch(`https://mydomain.com/MyDataService/${encodeURIComponent(key)}`, { method: "DELETE" }).then(handleErrors); } }) } class App extends React.Component { render() { return ( <List ... dataSource={listDataSource}> </List> ); } } export default App;
See Also
If you have technical questions, please create a support ticket in the DevExpress Support Center.