DevExtreme v24.1 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

Remote Grouping

Remote (server-side) operations can boost the DataGrid's performance on large datasets. In this demo, the DataGrid works with a million records seamlessly because they are processed on the server.

To notify the DataGrid that it works with a pre-processed dataset, set the remoteOperations property to true.

Backend API
import React from 'react'; import DataGrid, { Scrolling, RemoteOperations, Column, Grouping, GroupPanel, Summary, GroupItem, } from 'devextreme-react/data-grid'; import * as AspNetData from 'devextreme-aspnet-data-nojquery'; const dataSource = AspNetData.createStore({ key: 'Id', loadUrl: 'https://js.devexpress.com/Demos/WidgetsGalleryDataService/api/Sales', }); const App = () => ( <DataGrid height={420} width="100%" dataSource={dataSource} showBorders={true} wordWrapEnabled={true} > <RemoteOperations groupPaging={true} /> <Scrolling mode="virtual" /> <Grouping autoExpandAll={false} /> <GroupPanel visible={true} /> <Column dataField="Id" dataType="number" width={75} /> <Column dataField="ProductSubcategoryName" caption="Subcategory" width={150} /> <Column dataField="StoreName" caption="Store" width={150} groupIndex={0} /> <Column dataField="ProductCategoryName" caption="Category" width={120} groupIndex={1} /> <Column dataField="ProductName" caption="Product" /> <Column dataField="DateKey" caption="Date" dataType="date" format="yyyy-MM-dd" width={100} /> <Column dataField="SalesAmount" caption="Amount" format="currency" width={100} /> <Summary> <GroupItem column="Id" summaryType="count" /> </Summary> </DataGrid> ); export default App;
import React from 'react'; import DataGrid, { Scrolling, RemoteOperations, Column, Grouping, GroupPanel, Summary, GroupItem, } from 'devextreme-react/data-grid'; import * as AspNetData from 'devextreme-aspnet-data-nojquery'; const dataSource = AspNetData.createStore({ key: 'Id', loadUrl: 'https://js.devexpress.com/Demos/WidgetsGalleryDataService/api/Sales', }); const App = () => ( <DataGrid height={420} width="100%" dataSource={dataSource} showBorders={true} wordWrapEnabled={true} > <RemoteOperations groupPaging={true} /> <Scrolling mode="virtual" /> <Grouping autoExpandAll={false} /> <GroupPanel visible={true} /> <Column dataField="Id" dataType="number" width={75} /> <Column dataField="ProductSubcategoryName" caption="Subcategory" width={150} /> <Column dataField="StoreName" caption="Store" width={150} groupIndex={0} /> <Column dataField="ProductCategoryName" caption="Category" width={120} groupIndex={1} /> <Column dataField="ProductName" caption="Product" /> <Column dataField="DateKey" caption="Date" dataType="date" format="yyyy-MM-dd" width={100} /> <Column dataField="SalesAmount" caption="Amount" format="currency" width={100} /> <Summary> <GroupItem column="Id" summaryType="count" /> </Summary> </DataGrid> ); export default App;
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.tsx'; ReactDOM.render( <App />, document.getElementById('app'), );
window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, jsx: 'react', }, meta: { 'react': { 'esModule': true, }, 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, 'devextreme-aspnet-data-nojquery': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', }, defaultExtension: 'js', map: { 'ts': 'npm:plugin-typescript@4.2.4/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', 'react': 'npm:react@17.0.2/umd/react.development.js', 'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js', 'prop-types': 'npm:prop-types@15.8.1/prop-types.js', 'devextreme-aspnet-data-nojquery': 'npm:devextreme-aspnet-data-nojquery@3.0.0/index.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@1.28.1/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign@1.1.0', 'devextreme': 'npm:devextreme@24.1.4/cjs', 'devextreme-react': 'npm:devextreme-react@24.1.4/cjs', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.10/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.56/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.13', 'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate@7.4.11/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', 'devextreme-cldr-data': 'npm:devextreme-cldr-data@1.0.3', // SystemJS plugins 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'devextreme': { defaultExtension: 'js', }, 'devextreme-react': { main: 'index.js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/localization/messages': { format: 'json', defaultExtension: 'json', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.13/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, react: true, }, }; System.config(window.config);
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render(<App />, document.getElementById('app'));
<!DOCTYPE html> <html lang="en"> <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=5.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.1.4/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="https://unpkg.com/core-js@2.6.12/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.tsx"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"></div> </div> </body> </html>

You can also specify properties that allow the DataGrid to load data on demand to reduce the amount of transmitted data. Set the grouping.autoExpandAll property to false to collapse all the groups at startup. Data for each group is loaded only when the user expands the group. Enable the "virtual" scrolling.mode to load only those records that come into the viewport when the grid is scrolled vertically.

The DataGrid communicates with the server according to a protocol. Refer to the Server-Side Data Processing article for information on it.

NOTE

The data source in this demo is configured to return only 1000 records per request.