Example E5000
Visible to All Users

SelectBox for DevExtreme - How to implement standalone and in-form cascading SelectBoxes

This example demonstrates how to implement cascading SelectBoxes in the following scenarios:

  • Standalone SelectBoxes
  • SelectBoxes in Form

When you select a value from the first SelectBox, the second SelectBox loads the filtered values. In this example, only cities from the selected state appear in the second SelectBox.

Implement standalone and in-Form cascading SelectBoxes
To implement this functionality, get the value from the first editor and filter the dataSource by this value in the second editor.

Files to Review

Documentation

More Examples

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

jQuery/index.html
HTML
<!DOCTYPE html> <html> <head> <script src="https://code.jquery.com/jquery-3.3.1.js"></script> <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/19.2.6/js/dx.all.js"></script> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/19.2.6/css/dx.common.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/19.2.6/css/dx.light.css" /> <script> $(function(){ $("#stateSelectBox").dxSelectBox({ dataSource: states, valueExpr: "ID", displayExpr: "Name", showClearButton: true, onValueChanged: function(e) { let dataSource = citySelectBox.getDataSource(); dataSource.filter("StateID", "=", e.value); dataSource.load(); citySelectBox.option("value", null); } }); let citySelectBox = $("#citySelectBox").dxSelectBox({ dataSource: cities, valueExpr: "ID", displayExpr: "Name" }).dxSelectBox("instance"); $("#stateCityForm").dxForm({ formData: address, onFieldDataChanged: function(e) { if(e.dataField === "StateID") { let cityEditor = e.component.getEditor("CityID"); cityEditor.getDataSource().filter(['StateID', '=', e.value]); cityEditor.getDataSource().load(); e.component.updateData("CityID", null); } }, items:[ // State item { label: { text: "State" }, dataField: "StateID", editorType: "dxSelectBox", editorOptions: { dataSource: states, valueExpr: "ID", displayExpr: "Name", showClearButton: true } }, // City item { label: { text: "City" }, dataField: "CityID", editorType: "dxSelectBox", editorOptions: { dataSource: cities, valueExpr: "ID", displayExpr: "Name" } } ] }); }); var address = { StateID: null, CityID: null } var states = [{ "ID": 1, "Name": "Alabama" }, { "ID": 2, "Name": "Alaska" }, { "ID": 3, "Name": "Arizona" }, { "ID": 4, "Name": "Arkansas" }, { "ID": 5, "Name": "California" }]; var 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 }]; </script> </head> <body> <div class="dx-viewport demo-container"> <div class="dx-fieldset" style="width:50%"> <div class="dx-fieldset-header">Standalone editors</div> <div class="dx-field"> <div class="dx-field-label">State</div> <div class="dx-field-value"> <div id="stateSelectBox"></div> </div> </div> <div class="dx-field"> <div class="dx-field-label">City</div> <div class="dx-field-value"> <div id="citySelectBox"></div> </div> </div> <div class="dx-fieldset-header">In Form</div> <div class="dx-field"> <div id="stateCityForm"></div> </div> </div> </div> </body> </html>
Angular/src/app/app.component.html
HTML
<div class="dx-fieldset" style="width:50%"> <div class="dx-fieldset-header">Standalone editors</div> <div class="dx-field"> <div class="dx-field-label">State</div> <div class="dx-field-value"> <dx-select-box [dataSource]="states" displayExpr="Name" valueExpr="ID" (onValueChanged)="onStateChanged($event)" [showClearButton]="true" ></dx-select-box> </div> </div> <div class="dx-field"> <div class="dx-field-label">City</div> <div class="dx-field-value"> <dx-select-box #citySelectBox displayExpr="Name" valueExpr="ID" [(value)]="selectedCityID" [dataSource]="cities" ></dx-select-box> </div> </div> <div class="dx-fieldset-header">In Form</div> <div class="dx-field"> <dx-form [(formData)]="address" (onFieldDataChanged)="onFieldDataChanged($event)" > <dxi-item dataField="StateID" editorType="dxSelectBox" [editorOptions]='{ dataSource: states, valueExpr: "ID", displayExpr: "Name", showClearButton: true }' > <dxo-label text="State"></dxo-label> </dxi-item> <dxi-item dataField="CityID" editorType="dxSelectBox" [editorOptions]='{ dataSource: cities, valueExpr: "ID", displayExpr: "Name" }' > <dxo-label text="City"></dxo-label> </dxi-item> </dx-form> </div> </div>
Angular/src/app/app.component.ts
TypeScript
import { Component, ViewChild } from "@angular/core"; import { DxSelectBoxComponent } from "devextreme-angular/ui/select-box"; import { State, City, Address, Service } from "./app.service"; @Component({ selector: "app-root", templateUrl: "./app.component.html", styleUrls: ["./app.component.css"], providers: [Service] }) export class AppComponent { @ViewChild("citySelectBox", { static: false }) citySelectBoxComponent: DxSelectBoxComponent; states: State[]; cities: City[]; selectedCityID: number; address: Address; constructor(service: Service) { this.states = service.getStates(); this.cities = service.getCities(); this.address = service.getAddress(); } onStateChanged(e) { let dataSource = this.citySelectBoxComponent.instance.getDataSource(); dataSource.filter(["StateID", "=", e.value]); dataSource.load(); this.selectedCityID = null; } onFieldDataChanged(e) { if (e.dataField === "StateID") { var cityEditor = e.component.getEditor("CityID"); let dataSource = cityEditor.getDataSource(); dataSource.filter(["StateID", "=", e.value]); dataSource.load(); this.address.CityID = null; } } }
Vue/src/App.vue
Code
<template> <div> <div class="dx-fieldset" style="width:50%"> <div class="dx-fieldset-header">Select State, City</div> <div class="dx-field"> <div class="dx-field-label">State</div> <div class="dx-field-value"> <DxSelectBox :data-source="states" value-expr="ID" display-expr="Name" @valueChanged="stateValueChanged" /> </div> </div> <div class="dx-field"> <div class="dx-field-label">City</div> <div class="dx-field-value"> <DxSelectBox :ref="citySelectBoxRefKey" :data-source="cities" :value.sync="cityValue" value-expr="ID" display-expr="Name" /> </div> </div> <div class="dx-fieldset-header">In Form</div> <div class="dx-field"> <DxForm :form-data.sync="address" @field-data-changed="fieldDataChanged"> <DxSimpleItem data-field="StateID" editor-type="dxSelectBox" :editor-options="stateEditorOptions" > <DxLabel text="State"></DxLabel> </DxSimpleItem> <DxSimpleItem data-field="CityID" editor-type="dxSelectBox" :editor-options="cityEditorOptions" > <DxLabel text="City"></DxLabel> </DxSimpleItem> </DxForm> </div> </div> </div> </template> <script> import { DxSelectBox } from "devextreme-vue"; import DxForm, { DxSimpleItem, DxLabel } from "devextreme-vue/form"; import service from "./data.js"; const citySelectBoxRefKey = "city-select-box"; export default { components: { DxSelectBox, DxForm, DxSimpleItem, DxLabel }, data() { const states = service.getStates(), cities = service.getCities(); return { states, cities, cityValue: null, citySelectBoxRefKey, address: service.getAddress(), stateEditorOptions: { dataSource: states, valueExpr: "ID", displayExpr: "Name" }, cityEditorOptions: { dataSource: cities, valueExpr: "ID", displayExpr: "Name" } }; }, methods: { stateValueChanged: function(e) { this.cityDataSource.filter(["StateID", "=", e.value]); this.cityDataSource.load(); this.cityValue = null; }, fieldDataChanged: function(e) { if (e.dataField === "StateID") { var cityEditor = e.component.getEditor("CityID"); let dataSource = cityEditor.getDataSource(); dataSource.filter(["StateID", "=", e.value]); dataSource.load(); this.address.CityID = null; } } }, computed: { citySelectBox: function() { return this.$refs[citySelectBoxRefKey].instance; }, cityDataSource: function() { return this.citySelectBox.getDataSource(); } } }; </script>
React/src/App.js
JavaScript
import React, { useRef, useState, useCallback, useEffect } from "react"; import { SelectBox } from "devextreme-react/select-box"; import Form, { SimpleItem, Label } from "devextreme-react/form"; import 'devextreme/dist/css/dx.common.css'; import 'devextreme/dist/css/dx.light.css'; import service from "./data.js"; const states = service.getStates(); const cities = service.getCities(); const stateEditorOptions = { dataSource: states, valueExpr: "ID", displayExpr: "Name" }; const cityEditorOptions = { dataSource: cities, valueExpr: "ID", displayExpr: "Name" }; export default function App() { const [formData, setFormData] = useState(service.getAddress); const [stateValue, setStateValue] = useState(null); const [cityValue, setCityValue] = useState(null); const citySelectBoxRef = useRef(); let cityDataSource = null; useEffect(() => { cityDataSource = citySelectBoxRef.current.instance.getDataSource(); }, []) const stateValueChanged = (e) => { cityDataSource.filter(["StateID", "=", e.value]); cityDataSource.load(); setStateValue(e.value); setCityValue(null) } const cityValueChanged = e => { setCityValue(e.value); }; const onFieldDataChanged = useCallback((e) => { if (e.dataField === "StateID") { let cityEditor = e.component.getEditor("CityID"); let dataSource = cityEditor.getDataSource(); dataSource.filter(["StateID", "=", e.value]); dataSource.load(); setFormData({ ...formData, ...{ CityID: null, StateID: e.value } }); } }, []) return ( <div> <div className="dx-fieldset" style={{width:"50%"}}> <div className="dx-fieldset-header">Select State, City</div> <div className="dx-field"> <div className="dx-field-label">State</div> <div className="dx-field-value"> <SelectBox dataSource={states} valueExpr="ID" displayExpr="Name" value={stateValue} onValueChanged={stateValueChanged} /> </div> </div> <div className="dx-field"> <div className="dx-field-label">City</div> <div className="dx-field-value"> <SelectBox ref={citySelectBoxRef} dataSource={cities} onValueChanged={cityValueChanged} valueExpr="ID" displayExpr="Name" value={cityValue} /> </div> </div> <div className="dx-fieldset-header">In Form</div> <div className="dx-field"> <Form formData={formData} onFieldDataChanged={onFieldDataChanged} > <SimpleItem dataField="StateID" editorType="dxSelectBox" editorOptions={stateEditorOptions} > <Label text="State" /> </SimpleItem> <SimpleItem dataField="CityID" editorType="dxSelectBox" editorOptions={cityEditorOptions} > <Label text="City" /> </SimpleItem> </Form> </div> </div> </div> ); }
NetCore/CascadingSelectBoxesSample/Views/Home/Index.cshtml
Razor
@using CascadingSelectBoxesSample.Models <script> function onValueChanged(e) { let citySelectBox = $("#citySelectBox").dxSelectBox("instance"); let dataSource = citySelectBox.getDataSource(); dataSource.filter("StateID", "=", e.value); dataSource.load(); citySelectBox.option("value", null); } function onFieldDataChanged(e) { if (e.dataField === "StateID") { let cityEditor = e.component.getEditor("CityID"); let dataSource = cityEditor.getDataSource(); dataSource.filter(["StateID", "=", e.value]); dataSource.load(); e.component.updateData("CityID", null); } } </script> <div class="dx-viewport demo-container"> <div class="dx-fieldset" style="width:50%"> <div class="dx-fieldset-header">Standalone editors</div> <div class="dx-field"> <div class="dx-field-label">State</div> <div class="dx-field-value"> @(Html.DevExtreme().SelectBox() .DisplayExpr("Name") .ValueExpr("ID") .DataSource(State.States, "ID") .ShowClearButton(true) .OnValueChanged("onValueChanged")) </div> </div> <div class="dx-field"> <div class="dx-field-label">City</div> <div class="dx-field-value"> @(Html.DevExtreme().SelectBox().ID("citySelectBox") .DisplayExpr("Name") .ValueExpr("ID") .DataSource(City.Cities, "ID")) </div> </div> <div class="dx-fieldset-header">In Form</div> <div class="dx-field"> @(Html.DevExtreme().Form<Address>() .FormData(Address.Empty) .OnFieldDataChanged("onFieldDataChanged") .Items(items => { // State item items.AddSimpleFor(i => i.StateID) .Label(l => l.Text("State")) .Editor(e => e.SelectBox() .DataSource(State.States, "ID") .DisplayExpr("Name") .ValueExpr("ID") .ShowClearButton(true) ); // City item items.AddSimpleFor(i => i.CityID) .Label(l => l.Text("City")) .Editor(e => e.SelectBox() .DataSource(City.Cities, "ID") .DisplayExpr("Name") .ValueExpr("ID") ); }) ) </div> </div> </div>

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.