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 next example.

jQuery
JavaScript
$(function() {
    $("#schedulerContainer").dxScheduler({
        dataSource: new DevExpress.data.DataSource({
            store: new DevExpress.data.CustomStore({
                loadMode: "raw",   
                load: function () {
                    return $.getJSON('https://mydomain.com/MyDataService');
                }
            }), 
            paginate: false
        })
    });
});
Angular
TypeScript
HTML
import { ..., Inject } from "@angular/core";
import { HttpClient, HttpClientModule } from "@angular/common/http";
import { DxSchedulerModule } 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 {
    schedulerDataSource: any = {};
    constructor(@Inject(HttpClient) httpClient: HttpClient) {
        this.schedulerDataSource = new DataSource({
            store: new CustomStore({
                loadMode: "raw",   
                load: () => {
                    return httpClient.get('http://mydomain.com/MyDataService')
                        .toPromise();
                }
            }),
            paginate: false
        });
    }
}
@NgModule({
    imports: [
        // ...
        DxSchedulerModule,
        HttpClientModule
    ],
    // ...
})
<dx-scheduler ...
    [dataSource]="schedulerDataSource">
</dx-scheduler>
Vue
<template>
    <dx-scheduler ... 
        :data-source="dataSource" />
</template>
<script>
import { DxScheduler } from "devextreme-vue/scheduler";
import CustomStore from "devextreme/data/custom_store";
import DataSource from "devextreme/data/data_source";
// ...
function handleErrors(response) {
    if (!response.ok)
        throw Error(response.statusText);
    return response;
}
const schedulerDataSource = new DataSource({
    store: new CustomStore({
        loadMode: "raw",   
        load: () => {
            return fetch("https://mydomain.com/MyDataService")
                    .then(handleErrors);
        }
    }),
    paginate: false
});
export default {
    // ...
    data() {
        return {
            dataSource: schedulerDataSource
        };
    },
    components: {
        // ...
        DxScheduler
    }
}
</script>
React
import React from "react";
import Scheduler from "devextreme-react/scheduler";
import CustomStore from "devextreme/data/custom_store";
import DataSource from "devextreme/data/data_source";
// ...
function handleErrors(response) {
    if (!response.ok)
        throw Error(response.statusText);
    return response;
}
const schedulerDataSource = new DataSource({
    store: new CustomStore({
        loadMode: "raw",   
        load: () => {
            return fetch("https://mydomain.com/MyDataService")
                    .then(handleErrors);
        }
    }),
    paginate: false
});
class App extends React.Component {
    render() {
        return (
            <Scheduler ...
                dataSource={schedulerDataSource}>
            </Scheduler>
        );
    }
}
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. In case of the Scheduler, the only relevant setting is filter. It is passed when the Scheduler's remoteFiltering option is set to true.

After receiving this setting, the server should apply it to data and send back an object with the following structure:

{
    data: [ ... ] // result data objects
}

If the Scheduler allows a user to add, delete or update appointments, the CustomStore must implement the insert, remove and update operations as well. Here is a generalized configuration of the CustomStore for the Scheduler widget.

jQuery
var schedulerDataSource = new DevExpress.data.DataSource({
    paginate: false,
    load: function(loadOptions) {
        var d = $.Deferred(),
            params = {};
        if("filter" in loadOptions && isNotEmpty(loadOptions["filter"])) 
            params[i] = JSON.stringify(loadOptions[i]);
        $.getJSON("http://mydomain.com/MyDataService", params)
            .done(function(result) {
                // Here, you can perform operations unsupported by the server
                // or any other operations on the retrieved data
                d.resolve(result.data);
            });
        return d.promise();
    },
    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 isNotEmpty(value) {
    return value !== undefined && value !== null && value !== "";
}
$(function() {
    $("#schedulerContainer").dxScheduler({
        dataSource: schedulerDataSource,
        remoteFiltering: true
    });
});
Angular
TypeScript
HTML
import { ..., Inject } from "@angular/core";
import { HttpClient, HttpClientModule, HttpParams } from "@angular/common/http";
import { DxSchedulerModule } 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 {
    schedulerDataSource: any = {};
    constructor(@Inject(HttpClient) httpClient: HttpClient) {
        function isNotEmpty(value) {
            return value !== undefined && value !== null && value !== "";
        }
        this.schedulerDataSource = new DataSource({
            store: new CustomStore({
                load: (loadOptions) => {
                    let params: HttpParams = new HttpParams();
                    if("filter" in loadOptions && isNotEmpty(loadOptions["filter"])) 
                        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
                            // or any other operations on the retrieved data
                            return result.data;
                        });
                },
                insert: function(values) {
                    return httpClient.post('http://mydomain.com/MyDataService', values)
                        .toPromise();
                },
                remove: function(key) {
                    return httpClient.delete('http://mydomain.com/MyDataService' + encodeURIComponent(key))
                        .toPromise();
                },
                update: function(key, values) {
                    return httpClient.put('http://mydomain.com/MyDataService' + encodeURIComponent(key), values)
                        .toPromise();
                }
            }),
            paginate: false
        });
    }
}
@NgModule({
    imports: [
        // ...
        DxSchedulerModule,
        HttpClientModule
    ],
    // ...
})
<dx-scheduler
    [dataSource]="schedulerDataSource"
    [remoteFiltering]="true">
</dx-scheduler>
Vue
<template>
    <dx-scheduler ... 
        :data-source="dataSource" />
</template>
<script>
import DxScheduler from "devextreme-vue/scheduler";
import CustomStore from "devextreme/data/custom_store";
import DataSource from "devextreme/data/data_source";
// ...
function isNotEmpty(value) {
    return value !== undefined && value !== null && value !== "";
}
function handleErrors(response) {
    if (!response.ok)
        throw Error(response.statusText);
    return response;
}
const schedulerDataSource = new DataSource({
    store: new CustomStore({
        load: (loadOptions) => {
            let params = "?";
            if("filter" in loadOptions && isNotEmpty(loadOptions["filter"])) 
                params = params.set(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) => {
                    // Here, you can perform operations unsupported by the server
                    // or any other operations on the retrieved data
                    return result.data;
                });
        },
        insert: (values) => {
            return fetch("https://mydomain.com/MyDataService", {
                method: "POST",
                body: JSON.stringify(values),
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(handleErrors);
        },
        remove: (key) => {
            return fetch(`https://mydomain.com/MyDataService/${encodeURIComponent(key)}`, {
                method: "DELETE"
            }).then(handleErrors);
        },
        update: (key, values) => {
            return fetch(`https://mydomain.com/MyDataService/${encodeURIComponent(key)}`, {
                method: "PUT",
                body: JSON.stringify(values),
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(handleErrors);
        }
    }),
    paginate: false
})
export default {
    // ...
    data() {
        return {
            dataSource: schedulerDataSource
        };
    },
    components: {
        // ...
        DxScheduler
    }
}
</script>
React
import React from "react";
import Scheduler from "devextreme-react/scheduler";
import CustomStore from "devextreme/data/custom_store";
import DataSource from "devextreme/data/data_source";
// ...
function isNotEmpty(value) {
    return value !== undefined && value !== null && value !== "";
}
function handleErrors(response) {
    if (!response.ok) 
        throw Error(response.statusText);
    return response;
}
const schedulerDataSource = {
    store: new CustomStore({
        load: (loadOptions) => {
            let params = "?";
            if("filter" in loadOptions && isNotEmpty(loadOptions["filter"])) 
                params = params.set(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) => {
                    // Here, you can perform operations unsupported by the server
                    // or any other operations on the retrieved data
                    return result.data;
                });
        },
        insert: (values) => {
            return fetch("https://mydomain.com/MyDataService", {
                method: "POST",
                body: JSON.stringify(values),
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(handleErrors);
        },
        remove: (key) => {
            return fetch(`https://mydomain.com/MyDataService/${encodeURIComponent(key)}`, {
                method: "DELETE"
            }).then(handleErrors);
        },
        update: (key, values) => {
            return fetch(`https://mydomain.com/MyDataService/${encodeURIComponent(key)}`, {
                method: "PUT",
                body: JSON.stringify(values),
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(handleErrors);
        },
        paginate: false
    })
}
class App extends React.Component {
    render() {
        return (
            <Scheduler ...
                dataSource={schedulerDataSource}>
            </Scheduler>
        );
    }
}
export default App;

View Demo

See Also