If you have technical questions, please create a support ticket in the DevExpress Support Center.
import React, { useCallback, useState } from 'react';
import DataGrid, {
Column, DataGridTypes, FilterRow, Selection, Pager,
} from 'devextreme-react/data-grid';
import Button from 'devextreme-react/button';
import query from 'devextreme/data/query';
import 'devextreme/data/odata/store';
const MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24;
const dataSource = {
store: {
type: 'odata' as const,
version: 2,
url: 'https://js.devexpress.com/Demos/DevAV/odata/Tasks',
key: 'Task_ID',
},
expand: 'ResponsibleEmployee',
select: [
'Task_ID',
'Task_Subject',
'Task_Start_Date',
'Task_Due_Date',
'Task_Status',
'ResponsibleEmployee/Employee_Full_Name',
],
};
const selectionFilter = ['Task_Status', '=', 'Completed'];
let dataGrid;
const App = () => {
const [taskCount, setTaskCount] = useState(0);
const [peopleCount, setPeopleCount] = useState(0);
const [avgDuration, setAvgDuration] = useState(0);
const calculateStatistics = useCallback(async () => {
const selectedItems = await dataGrid.getSelectedRowsData();
const totalDuration = selectedItems.reduce((currentValue: number, item: { Task_Due_Date: number; Task_Start_Date: number; }) => {
const duration = item.Task_Due_Date - item.Task_Start_Date;
return currentValue + duration;
}, 0);
const averageDurationInDays = totalDuration / MILLISECONDS_IN_DAY / selectedItems.length;
setTaskCount(selectedItems.length);
setPeopleCount(
query(selectedItems)
.groupBy('ResponsibleEmployee.Employee_Full_Name')
.toArray().length,
);
setAvgDuration(Math.round(averageDurationInDays) || 0);
}, []);
const onInitialized = useCallback((e: DataGridTypes.InitializedEvent) => {
dataGrid = e.component;
calculateStatistics();
}, [calculateStatistics]);
return (
<div>
<DataGrid
id="grid-container"
dataSource={dataSource}
showBorders={true}
defaultSelectionFilter={selectionFilter}
onInitialized={onInitialized}
>
<Selection mode="multiple" deferred={true} />
<FilterRow visible={true} />
<Pager visible={true} />
<Column caption="Subject" dataField="Task_Subject" />
<Column
caption="Start Date"
dataField="Task_Start_Date"
width="auto"
dataType="date"
/>
<Column
caption="Due Date"
dataField="Task_Due_Date"
width="auto"
dataType="date"
/>
<Column
caption="Assigned To"
dataField="ResponsibleEmployee.Employee_Full_Name"
width="auto"
allowSorting={false}
/>
<Column caption="Status" width="auto" dataField="Task_Status" />
</DataGrid>
<div className="selection-summary center">
<Button
id="calculateButton"
text="Get statistics on the selected tasks"
type="default"
onClick={calculateStatistics}
/>
<div>
<div className="column">
<span className="text count">Task count:</span>
<span className="value">{taskCount}</span>
</div>
<div className="column">
<span className="text people-count">People assigned:</span>
<span className="value">{peopleCount}</span>
</div>
<div className="column">
<span className="text avg-duration">Average task duration (days):</span>
<span className="value">{avgDuration}</span>
</div>
</div>
</div>
</div>
);
};
export default App;
xxxxxxxxxx
import React, { useCallback, useState } from 'react';
import DataGrid, {
Column, FilterRow, Selection, Pager,
} from 'devextreme-react/data-grid';
import Button from 'devextreme-react/button';
import query from 'devextreme/data/query';
import 'devextreme/data/odata/store';
const MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24;
const dataSource = {
store: {
type: 'odata',
version: 2,
url: 'https://js.devexpress.com/Demos/DevAV/odata/Tasks',
key: 'Task_ID',
},
expand: 'ResponsibleEmployee',
select: [
'Task_ID',
'Task_Subject',
'Task_Start_Date',
'Task_Due_Date',
'Task_Status',
'ResponsibleEmployee/Employee_Full_Name',
],
};
const selectionFilter = ['Task_Status', '=', 'Completed'];
let dataGrid;
const App = () => {
const [taskCount, setTaskCount] = useState(0);
const [peopleCount, setPeopleCount] = useState(0);
const [avgDuration, setAvgDuration] = useState(0);
const calculateStatistics = useCallback(async () => {
const selectedItems = await dataGrid.getSelectedRowsData();
const totalDuration = selectedItems.reduce((currentValue, item) => {
const duration = item.Task_Due_Date - item.Task_Start_Date;
return currentValue + duration;
}, 0);
const averageDurationInDays = totalDuration / MILLISECONDS_IN_DAY / selectedItems.length;
setTaskCount(selectedItems.length);
setPeopleCount(
query(selectedItems).groupBy('ResponsibleEmployee.Employee_Full_Name').toArray().length,
);
setAvgDuration(Math.round(averageDurationInDays) || 0);
}, []);
const onInitialized = useCallback(
(e) => {
dataGrid = e.component;
calculateStatistics();
},
[calculateStatistics],
);
return (
<div>
<DataGrid
id="grid-container"
dataSource={dataSource}
showBorders={true}
defaultSelectionFilter={selectionFilter}
onInitialized={onInitialized}
>
<Selection
mode="multiple"
deferred={true}
/>
<FilterRow visible={true} />
<Pager visible={true} />
<Column
caption="Subject"
dataField="Task_Subject"
/>
<Column
caption="Start Date"
dataField="Task_Start_Date"
width="auto"
dataType="date"
/>
<Column
caption="Due Date"
dataField="Task_Due_Date"
width="auto"
dataType="date"
/>
<Column
caption="Assigned To"
dataField="ResponsibleEmployee.Employee_Full_Name"
width="auto"
allowSorting={false}
/>
<Column
caption="Status"
width="auto"
dataField="Task_Status"
/>
</DataGrid>
<div className="selection-summary center">
<Button
id="calculateButton"
text="Get statistics on the selected tasks"
type="default"
onClick={calculateStatistics}
/>
<div>
<div className="column">
<span className="text count">Task count:</span>
<span className="value">{taskCount}</span>
</div>
<div className="column">
<span className="text people-count">People assigned:</span>
<span className="value">{peopleCount}</span>
</div>
<div className="column">
<span className="text avg-duration">Average task duration (days):</span>
<span className="value">{avgDuration}</span>
</div>
</div>
</div>
</div>
);
};
export default App;
xxxxxxxxxx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.tsx';
ReactDOM.render(
<App />,
document.getElementById('app'),
);
xxxxxxxxxx
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,
},
'openai': {
'esModule': true,
},
},
paths: {
'npm:': 'https://unpkg.com/',
'bundles:': 'bundles/',
'externals:': 'bundles/externals/',
},
defaultExtension: 'js',
map: {
'ts': 'npm:plugin-typescript@8.0.0/lib/plugin.js',
'typescript': 'npm:typescript@4.2.4/lib/typescript.js',
'jszip': 'npm:jszip@3.10.1/dist/jszip.min.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/prop-types.js',
'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js',
'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js',
'es6-object-assign': 'npm:es6-object-assign',
'devextreme': 'npm:devextreme@link:../../packages/devextreme/artifacts/npm/devextreme/cjs',
'devextreme-react': 'npm:devextreme-react@link:../../packages/devextreme-react/npm/cjs',
'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js',
'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js',
'devexpress-gantt': 'npm:devexpress-gantt@4.1.54/dist/dx-gantt.js',
'@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12',
'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/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.12/inferno/package.json',
],
babelOptions: {
sourceMaps: false,
stage0: true,
react: true,
},
};
System.config(window.config);
xxxxxxxxxx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';
ReactDOM.render(<App />, document.getElementById('app'));
xxxxxxxxxx
<html lang="en">
<head></head>
<body class="dx-viewport">
<div class="demo-container">
<div id="app"></div>
</div>
</body>
</html>
xxxxxxxxxx
#grid-container {
height: 400px;
}
.center {
text-align: center;
}
.selection-summary {
border: 1px solid rgba(161, 161, 161, 0.2);
padding: 25px;
}
.column {
margin: 20px 30px 0 0;
display: inline-block;
white-space: nowrap;
text-align: right;
}
.value {
font-size: 40px;
display: inline-block;
vertical-align: middle;
}
.text {
text-align: left;
white-space: normal;
display: inline-block;
vertical-align: middle;
}
.avg-duration {
width: 100px;
}
.count {
width: 40px;
}
.people-count {
width: 65px;
}
This demo illustrates the second scenario. Deferred selection is enabled and the selected rows are only requested when you click the button below the grid.
To enable deferred selection in your application, set the selection.deferred property to true.
To specify the initially selected rows, use the selectionFilter property. The DataGrid updates this property's value at runtime and you can always access the applied filter. In this demo, the selectionFilter selects rows whose Status
is Completed
.
To load the selected rows' data, call the getSelectedRowsData() method. In deferred selection mode, this method returns a Promise. You can access row data in its fulfillment handler. In this demo, the getSelectedRowsData() method gets data objects that are then used to calculate statistics for the selected tasks.