Cascading Comboboxes
- 3 minutes to read
The <DxComboBox>
allows you to create cascade lists - populate one ComboBox with items based on the user selection from another ComboBox. Use the Value property to access the selected item. To respond to the selected item change, handle the ValueChanged event.
@using CountryCityData
<div class="row cw-480">
<div class="col-md-6">
<label for="cbCountryName" class="mb-1">
Country Name
</label>
<DxComboBox Data="@Countries"
TextFieldName="@nameof(Country.CountryName)"
Value="@CurrentCountry"
ValueChanged="@((Country country) => SelectedCountryChanged(country))"
AllowUserInput="true">
InputId="cbCountryName">
</DxComboBox>
</div>
<div class="col-md-6">
<label for="cbCityName" class="mb-1">
City Name
</label>
<DxComboBox Data="@CurrentCountryCities"
TextFieldName="@nameof(City.CityName)"
@bind-Value="@CurrentCity"
AllowUserInput="true"
InputId="cbCityName" >
</DxComboBox>
</div>
</div>
@code {
List<Country> Countries { get; set; } = CountryData.Countries;
List<City> CurrentCountryCities { get; set; } = new List<City>();
Country CurrentCountry { get; set; } = CountryData.Countries[1];
City CurrentCity { get; set; } = CityData.Cities[4];
protected override void OnInitialized() {
base.OnInitialized();
SelectedCountryChanged(CurrentCountry);
}
void SelectedCountryChanged(Country country) {
CurrentCountry = country;
CurrentCountryCities = CityData.Cities.FindAll(city => city.CountryId == CurrentCountry.Id);
CurrentCity = CurrentCountryCities[0];
}
}
If you use the DataAsync or CustomData property to bind cascading ComboBoxes to data, you need to set a key to force the component to fetch data on re-render, or use the Data property instead of the DataAsync
delegate. Refer to this breaking change for more information.
<DxComboBox Data="FirstDataSource"
ValueFieldName="@nameof(MyModel.ID)"
TextFieldName="@nameof(MyModel.Name)"
Value="@FirstValue"
ValueChanged="@((int? value) => { FirstValue = value; keyValue++;})" />
<DxComboBox @key=@keyValue
DataAsync="(cancellationToken) => LoadDataAsync(FirstValue, cancellationToken)"
ValueFieldName="@nameof(MyModel.ID)"
TextFieldName="@nameof(MyModel.Name)"
@bind-Value="@SecondValue" />
@code {
int keyValue;
IEnumerable<MyModel> FirstDataSource { get; set; }
int? FirstValue { get; set; }
string? SecondValue { get; set; }
public class MyModel {
public int ID { get; set; }
public string Name { get; set; }
}
protected override void OnInitialized() {
FirstDataSource = Enumerable.Range(0, 10).Select(i => new MyModel() { ID = i, Name = $"Name {i}" });
}
public async Task<IEnumerable<string>> LoadDataAsync(int? value, CancellationToken cancellationToken = default(CancellationToken)) {
if(!value.HasValue)
return Enumerable.Empty<string>();
return FirstDataSource.Where(i => i.ID % value == 0).Select(i => i.Name);
}
}