Your search did not match any results.
Data Grid

CRUD Operations

Documentation

This demo shows how to implement remote CRUD operations in the CustomStore. You can view the server implementation under the DataGridWebApiController tab in the ASP.NET MVC version of this demo. The requests sent to the server are displayed under the DataGrid.

After a cell is edited, the DataGrid can behave differently depending on the selected refresh mode: reload data from the server (the refreshMode is full), reapply data processing operations (reshape), or merely rerender the changed cells (repaint).

Apply
Reset
import React from 'react'; import { DataGrid, Column, Editing, Scrolling, Lookup, Summary, TotalItem } from 'devextreme-react/data-grid'; import { Button } from 'devextreme-react/button'; import { SelectBox } from 'devextreme-react/select-box'; import CustomStore from 'devextreme/data/custom_store'; import { formatDate } from 'devextreme/localization'; import 'whatwg-fetch'; const URL = 'https://js.devexpress.com/Demos/Mvc/api/DataGridWebApi'; const REFRESH_MODES = ['full', 'reshape', 'repaint']; class App extends React.Component { constructor(props) { super(props); this.state = { ordersData: new CustomStore({ key: 'OrderID', load: () => this.sendRequest(`${URL}/Orders`), insert: (values) => this.sendRequest(`${URL}/InsertOrder`, 'POST', { values: JSON.stringify(values) }), update: (key, values) => this.sendRequest(`${URL}/UpdateOrder`, 'PUT', { key: key, values: JSON.stringify(values) }), remove: (key) => this.sendRequest(`${URL}/DeleteOrder`, 'DELETE', { key: key }) }), customersData: new CustomStore({ key: 'Value', loadMode: 'raw', load: () => this.sendRequest(`${URL}/CustomersLookup`) }), shippersData: new CustomStore({ key: 'Value', loadMode: 'raw', load: () => this.sendRequest(`${URL}/ShippersLookup`) }), requests: [], refreshMode: 'reshape' }; this.clearRequests = this.clearRequests.bind(this); this.handleRefreshModeChange = this.handleRefreshModeChange.bind(this); } sendRequest(url, method, data) { method = method || 'GET'; data = data || {}; this.logRequest(method, url, data); if(method === 'GET') { return fetch(url, { method: method, credentials: 'include' }).then(result => result.json().then(json => { if(result.ok) return json.data; throw json.Message; })); } const params = Object.keys(data).map((key) => { return `${encodeURIComponent(key) }=${ encodeURIComponent(data[key])}`; }).join('&'); return fetch(url, { method: method, body: params, headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, credentials: 'include' }).then(result => { if(result.ok) { return result.text().then(text => text && JSON.parse(text)); } else { return result.json().then(json => { throw json.Message; }); } }); } logRequest(method, url, data) { const args = Object.keys(data || {}).map(function(key) { return `${key }=${ data[key]}`; }).join(' '); const time = formatDate(new Date(), 'HH:mm:ss'); const request = [time, method, url.slice(URL.length), args].join(' '); this.setState((state) => { return { requests: [request].concat(state.requests) }; }); } clearRequests() { this.setState({ requests: [] }); } handleRefreshModeChange(e) { this.setState({ refreshMode: e.value }); } render() { const { refreshMode, ordersData, customersData, shippersData } = this.state; return ( <React.Fragment> <DataGrid id={'grid'} showBorders={true} dataSource={ordersData} repaintChangesOnly={true} > <Editing refreshMode={refreshMode} mode={'cell'} allowAdding={true} allowDeleting={true} allowUpdating={true} /> <Scrolling mode={'virtual'} /> <Column dataField={'CustomerID'} caption={'Customer'}> <Lookup dataSource={customersData} valueExpr={'Value'} displayExpr={'Text'} /> </Column> <Column dataField={'OrderDate'} dataType={'date'}> </Column> <Column dataField={'Freight'}> </Column> <Column dataField={'ShipCountry'}> </Column> <Column dataField={'ShipVia'} caption={'Shipping Company'} dataType={'number'} > <Lookup dataSource={shippersData} valueExpr={'Value'} displayExpr={'Text'} /> </Column> <Summary> <TotalItem column={'CustomerID'} summaryType={'count'} /> <TotalItem column={'Freight'} summaryType={'sum'} valueFormat={'#0.00'} /> </Summary> </DataGrid> <div className={'options'}> <div className={'caption'}>Options</div> <div className={'option'}> <span>Refresh Mode: </span> <SelectBox value={refreshMode} items={REFRESH_MODES} onValueChanged={this.handleRefreshModeChange} /> </div> <div id={'requests'}> <div> <div className={'caption'}>Network Requests</div> <Button id={'clear'} text={'Clear'} onClick={this.clearRequests} /> </div> <ul> {this.state.requests.map((request, index) => <li key={index}>{request}</li>)} </ul> </div> </div> </React.Fragment> ); } } export default App;
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render( <App />, document.getElementById('app') );
<!DOCTYPE html> <html> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/19.2.3/css/dx.common.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/19.2.3/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import('./index.js'); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"></div> </div> </body> </html>
#grid { height: 440px; } .options { padding: 20px; margin-top: 20px; background-color: rgba(191, 191, 191, 0.15); } .caption { margin-bottom: 10px; font-weight: 500; font-size: 18px; } .option { margin-bottom: 10px; } .option > span { position: relative; top: 2px; margin-right: 10px; } .option > .dx-widget { display: inline-block; vertical-align: middle; } #requests .caption { float: left; padding-top: 7px; } #requests > div { padding-bottom: 5px; } #requests > div:after { content: ""; display: table; clear: both; } #requests #clear { float: right; } #requests ul { list-style: none; max-height: 100px; overflow: auto; margin: 0; } #requests ul li { padding: 7px 0; border-bottom: 1px solid #dddddd; } #requests ul li:last-child { border-bottom: none; }
System.config({ transpiler: 'plugin-babel', paths: { 'npm:': 'https://unpkg.com/' }, defaultExtension: 'js', map: { 'react': 'npm:react@16/umd/react.development.js', 'react-dom': 'npm:react-dom@16/umd/react-dom.development.js', 'prop-types': 'npm:prop-types/prop-types.js', 'devextreme': 'npm:devextreme@19.2', 'devextreme-react': 'npm:devextreme-react@19.2', 'jszip': 'npm:jszip@3.1.3/dist/jszip.min.js', 'quill': 'npm:quill@1.3.7/dist/quill.js', 'devexpress-diagram': 'npm:devexpress-diagram', 'devexpress-gantt': 'npm:devexpress-gantt', 'whatwg-fetch': 'npm:whatwg-fetch@2.0.4/fetch.js', // SystemJS plugins 'plugin-babel': 'npm:systemjs-plugin-babel@0/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0/systemjs-babel-browser.js' }, packages: { 'devextreme': { defaultExtension: 'js' }, 'devextreme-react': { main: 'index.js' } }, babelOptions: { sourceMaps: false, stage0: true, react: true } });