If you have technical questions, please create a support ticket in the DevExpress Support Center.
import React from 'react';
import DataGrid, {
Column, DataGridTypes, Editing, Lookup,
} from 'devextreme-react/data-grid';
import {
employees, states, cities, Employee,
} from './data.ts';
const onEditorPreparing = (e: DataGridTypes.EditorPreparingEvent) => {
if (e.parentType === 'dataRow' && e.dataField === 'CityID') {
const isStateNotSet = e.row.data.StateID === undefined;
e.editorOptions.disabled = isStateNotSet;
}
};
const getFilteredCities = (options: { data?: Employee; }) => ({
store: cities,
filter: options.data ? ['StateID', '=', options.data.StateID] : null,
});
function setStateValue(rowData: Employee, value) {
rowData.CityID = null;
this.defaultSetCellValue(rowData, value);
}
const App = () => (
<div id="data-grid-demo">
<DataGrid
dataSource={employees}
keyExpr="ID"
showBorders={true}
onEditorPreparing={onEditorPreparing}
>
<Editing
mode="row"
allowUpdating={true}
allowAdding={true}>
</Editing>
<Column dataField="FirstName" />
<Column dataField="LastName" />
<Column dataField="Position" />
<Column dataField="StateID" caption="State" setCellValue={setStateValue}>
<Lookup dataSource={states} displayExpr="Name" valueExpr="ID" />
</Column>
<Column dataField="CityID" caption="City">
<Lookup dataSource={getFilteredCities as any} displayExpr="Name" valueExpr="ID" />
</Column>
</DataGrid>
</div>
);
export default App;
xxxxxxxxxx
import React from 'react';
import DataGrid, { Column, Editing, Lookup } from 'devextreme-react/data-grid';
import { employees, states, cities } from './data.js';
const onEditorPreparing = (e) => {
if (e.parentType === 'dataRow' && e.dataField === 'CityID') {
const isStateNotSet = e.row.data.StateID === undefined;
e.editorOptions.disabled = isStateNotSet;
}
};
const getFilteredCities = (options) => ({
store: cities,
filter: options.data ? ['StateID', '=', options.data.StateID] : null,
});
function setStateValue(rowData, value) {
rowData.CityID = null;
this.defaultSetCellValue(rowData, value);
}
const App = () => (
<div id="data-grid-demo">
<DataGrid
dataSource={employees}
keyExpr="ID"
showBorders={true}
onEditorPreparing={onEditorPreparing}
>
<Editing
mode="row"
allowUpdating={true}
allowAdding={true}
></Editing>
<Column dataField="FirstName" />
<Column dataField="LastName" />
<Column dataField="Position" />
<Column
dataField="StateID"
caption="State"
setCellValue={setStateValue}
>
<Lookup
dataSource={states}
displayExpr="Name"
valueExpr="ID"
/>
</Column>
<Column
dataField="CityID"
caption="City"
>
<Lookup
dataSource={getFilteredCities}
displayExpr="Name"
valueExpr="ID"
/>
</Column>
</DataGrid>
</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
export interface Employee {
ID:number;
FirstName: string;
LastName: string;
Prefix: string;
Position: string;
StateID:number;
CityID: number;
}
export const employees: Employee[] = [{
ID: 1,
FirstName: 'John',
LastName: 'Heart',
Prefix: 'Mr.',
Position: 'CTO',
StateID: 5,
CityID: 17,
}, {
ID: 2,
FirstName: 'Olivia',
LastName: 'Peyton',
Prefix: 'Mrs.',
Position: 'HR Manager',
StateID: 5,
CityID: 17,
}, {
ID: 3,
FirstName: 'Robert',
LastName: 'Reagan',
Prefix: 'Mr.',
Position: 'IT Manager',
StateID: 4,
CityID: 14,
}, {
ID: 4,
FirstName: 'Greta',
LastName: 'Sims',
Prefix: 'Ms.',
Position: 'Shipping Manager',
StateID: 3,
CityID: 8,
}, {
ID: 5,
FirstName: 'Brett',
LastName: 'Wade',
Prefix: 'Mr.',
Position: 'Shipping Manager',
StateID: 3,
CityID: 9,
}, {
ID: 6,
FirstName: 'Sandra',
LastName: 'Johnson',
Prefix: 'Mrs.',
Position: 'Network Admin',
StateID: 2,
CityID: 6,
}, {
ID: 7,
FirstName: 'Kevin',
LastName: 'Carter',
Prefix: 'Mr.',
Position: 'Network Admin',
StateID: 1,
CityID: 3,
}, {
ID: 8,
FirstName: 'Cynthia',
LastName: 'Stanwick',
Prefix: 'Ms.',
Position: 'Sales Assistant',
StateID: 1,
CityID: 3,
}, {
ID: 9,
FirstName: 'Kent',
LastName: 'Samuelson',
Prefix: 'Dr.',
Position: 'Sales Assistant',
StateID: 1,
CityID: 2,
}, {
ID: 10,
FirstName: 'Taylor',
LastName: 'Riley',
Prefix: 'Mr.',
Position: 'Support Assistant',
StateID: 5,
CityID: 17,
}, {
ID: 11,
FirstName: 'Sam',
LastName: 'Hill',
Prefix: 'Mr.',
Position: 'Sales Assistant',
StateID: 2,
CityID: 5,
}, {
ID: 12,
FirstName: 'Kelly',
LastName: 'Rodriguez',
Prefix: 'Ms.',
Position: 'Sales Assistant',
StateID: 5,
CityID: 17,
}, {
ID: 13,
FirstName: 'Natalie',
LastName: 'Maguirre',
Prefix: 'Mrs.',
Position: 'Sales Assistant',
StateID: 4,
CityID: 14,
}, {
ID: 14,
FirstName: 'Walter',
LastName: 'Hobbs',
Prefix: 'Mr.',
Position: 'Support Assistant',
StateID: 2,
CityID: 5,
}];
export const states = [{
ID: 1,
Name: 'Alabama',
}, {
ID: 2,
Name: 'Alaska',
}, {
ID: 3,
Name: 'Arizona',
}, {
ID: 4,
Name: 'Arkansas',
}, {
ID: 5,
Name: 'California',
}];
export const cities = [{
ID: 1,
Name: 'Tuscaloosa',
StateID: 1,
}, {
ID: 2,
Name: 'Hoover',
StateID: 1,
}, {
ID: 3,
Name: 'Dothan',
StateID: 1,
}, {
ID: 4,
Name: 'Decatur',
StateID: 1,
}, {
ID: 5,
Name: 'Anchorage',
StateID: 2,
}, {
ID: 6,
Name: 'Fairbanks',
StateID: 2,
}, {
ID: 7,
Name: 'Juneau',
StateID: 2,
}, {
ID: 8,
Name: 'Avondale',
StateID: 3,
}, {
ID: 9,
Name: 'Buckeye',
StateID: 3,
}, {
ID: 10,
Name: 'Carefree',
StateID: 3,
}, {
ID: 11,
Name: 'Springdale',
StateID: 4,
}, {
ID: 12,
Name: 'Rogers',
StateID: 4,
}, {
ID: 13,
Name: 'Sherwood',
StateID: 4,
}, {
ID: 14,
Name: 'Jacksonville',
StateID: 4,
}, {
ID: 15,
Name: 'Cabot',
StateID: 4,
}, {
ID: 16,
Name: 'Adelanto',
StateID: 5,
}, {
ID: 17,
Name: 'Glendale',
StateID: 5,
}, {
ID: 18,
Name: 'Moorpark',
StateID: 5,
}, {
ID: 19,
Name: 'Needles',
StateID: 5,
}, {
ID: 20,
Name: 'Ontario',
StateID: 5,
}];
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
export const employees = [
{
ID: 1,
FirstName: 'John',
LastName: 'Heart',
Prefix: 'Mr.',
Position: 'CTO',
StateID: 5,
CityID: 17,
},
{
ID: 2,
FirstName: 'Olivia',
LastName: 'Peyton',
Prefix: 'Mrs.',
Position: 'HR Manager',
StateID: 5,
CityID: 17,
},
{
ID: 3,
FirstName: 'Robert',
LastName: 'Reagan',
Prefix: 'Mr.',
Position: 'IT Manager',
StateID: 4,
CityID: 14,
},
{
ID: 4,
FirstName: 'Greta',
LastName: 'Sims',
Prefix: 'Ms.',
Position: 'Shipping Manager',
StateID: 3,
CityID: 8,
},
{
ID: 5,
FirstName: 'Brett',
LastName: 'Wade',
Prefix: 'Mr.',
Position: 'Shipping Manager',
StateID: 3,
CityID: 9,
},
{
ID: 6,
FirstName: 'Sandra',
LastName: 'Johnson',
Prefix: 'Mrs.',
Position: 'Network Admin',
StateID: 2,
CityID: 6,
},
{
ID: 7,
FirstName: 'Kevin',
LastName: 'Carter',
Prefix: 'Mr.',
Position: 'Network Admin',
StateID: 1,
CityID: 3,
},
{
ID: 8,
FirstName: 'Cynthia',
LastName: 'Stanwick',
Prefix: 'Ms.',
Position: 'Sales Assistant',
StateID: 1,
CityID: 3,
},
{
ID: 9,
FirstName: 'Kent',
LastName: 'Samuelson',
Prefix: 'Dr.',
Position: 'Sales Assistant',
StateID: 1,
CityID: 2,
},
{
ID: 10,
FirstName: 'Taylor',
LastName: 'Riley',
Prefix: 'Mr.',
Position: 'Support Assistant',
StateID: 5,
CityID: 17,
},
{
ID: 11,
FirstName: 'Sam',
LastName: 'Hill',
Prefix: 'Mr.',
Position: 'Sales Assistant',
StateID: 2,
CityID: 5,
},
{
ID: 12,
FirstName: 'Kelly',
LastName: 'Rodriguez',
Prefix: 'Ms.',
Position: 'Sales Assistant',
StateID: 5,
CityID: 17,
},
{
ID: 13,
FirstName: 'Natalie',
LastName: 'Maguirre',
Prefix: 'Mrs.',
Position: 'Sales Assistant',
StateID: 4,
CityID: 14,
},
{
ID: 14,
FirstName: 'Walter',
LastName: 'Hobbs',
Prefix: 'Mr.',
Position: 'Support Assistant',
StateID: 2,
CityID: 5,
},
];
export const states = [
{
ID: 1,
Name: 'Alabama',
},
{
ID: 2,
Name: 'Alaska',
},
{
ID: 3,
Name: 'Arizona',
},
{
ID: 4,
Name: 'Arkansas',
},
{
ID: 5,
Name: 'California',
},
];
export const cities = [
{
ID: 1,
Name: 'Tuscaloosa',
StateID: 1,
},
{
ID: 2,
Name: 'Hoover',
StateID: 1,
},
{
ID: 3,
Name: 'Dothan',
StateID: 1,
},
{
ID: 4,
Name: 'Decatur',
StateID: 1,
},
{
ID: 5,
Name: 'Anchorage',
StateID: 2,
},
{
ID: 6,
Name: 'Fairbanks',
StateID: 2,
},
{
ID: 7,
Name: 'Juneau',
StateID: 2,
},
{
ID: 8,
Name: 'Avondale',
StateID: 3,
},
{
ID: 9,
Name: 'Buckeye',
StateID: 3,
},
{
ID: 10,
Name: 'Carefree',
StateID: 3,
},
{
ID: 11,
Name: 'Springdale',
StateID: 4,
},
{
ID: 12,
Name: 'Rogers',
StateID: 4,
},
{
ID: 13,
Name: 'Sherwood',
StateID: 4,
},
{
ID: 14,
Name: 'Jacksonville',
StateID: 4,
},
{
ID: 15,
Name: 'Cabot',
StateID: 4,
},
{
ID: 16,
Name: 'Adelanto',
StateID: 5,
},
{
ID: 17,
Name: 'Glendale',
StateID: 5,
},
{
ID: 18,
Name: 'Moorpark',
StateID: 5,
},
{
ID: 19,
Name: 'Needles',
StateID: 5,
},
{
ID: 20,
Name: 'Ontario',
StateID: 5,
},
];
xxxxxxxxxx
<html lang="en">
<head></head>
<body class="dx-viewport">
<div class="demo-container">
<div id="app"></div>
</div>
</body>
</html>
xxxxxxxxxx
#data-grid-demo {
min-height: 700px;
}
This demo shows how to implement cascading lookups:
-
Configure the primary lookup
A column's lookup is configured in the lookup object. Assign an array of items to the lookup's dataSource. Then specify the valueExpr and displayExpr properties if the data source contains objects. (See theStateID
column.) -
Configure the secondary lookup
The secondary lookup has a similar configuration, but its dataSource should be a function so that you can dynamically filter the lookup. (See step 3.) -
Connect the lookups
To filter the secondary lookup's items based on the primary lookup's value, specify the filter property in the secondary lookup's dataSource. (See theCityID
column). -
Reset the secondary lookup when the primary lookup's value is changed
Use the setCellValue function as shown in theStateID
column's configuration. -
Disable the secondary lookup until the primary lookup's value is set
Use the onEditorPreparing handler for this.
After you configure lookups, enable edit operations. Specify the required editing.mode and set the editing object's allowUpdating, allowAdding, and allowDeleting properties to true.