Skip to content

Commit 4aa33e2

Browse files
kb(dropdowns): cascading dropdowns
1 parent 51f54d0 commit 4aa33e2

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
---
2+
title: Cascading DropdDown
3+
description: how to make a cascading a dropdown or combo box
4+
type: how-to
5+
page_title: Cascading DropDown or ComboBox
6+
slug: dropdown-kb-cascading
7+
position:
8+
tags:
9+
res_type: kb
10+
---
11+
12+
## Environment
13+
<table>
14+
<tbody>
15+
<tr>
16+
<td>Product</td>
17+
<td>DropDownList for Blazor, ComboBox for Blazor</td>
18+
</tr>
19+
</tbody>
20+
</table>
21+
22+
23+
## Description
24+
25+
How to make cascading dropdown or combobox components? The data from one should filter the selection of the next and enable them.
26+
27+
## Solution
28+
29+
Use the `ValueChanged` event to update the model value and to filter the data for the next dropdown. Additionally, you can also use its `Enabled` parameter and tie it to the value of its "parent".
30+
31+
>caption Cascading DropDowns
32+
33+
````CSHTML
34+
@* Cascading componentsare disabled based on the selection of their parents. Events on parent components
35+
trigger data loading for child components so they show relevant result only.
36+
You can also see how to get the selected model from a dropdown component.
37+
This sample works with a ComboBox as well *@
38+
39+
<TelerikDropDownList Value="@CurrentOrder.CategoryId" Data="@Categories" DefaultText="Select Category"
40+
TextField="CategoryName" ValueField="CategoryId"
41+
ValueChanged="@( (int c) => CategorySelected(c) )">
42+
</TelerikDropDownList>
43+
44+
<TelerikDropDownList Value="@CurrentOrder.ProductId" Data="@CurrentProducts" DefaultText="Select Product"
45+
TextField="ProductName" ValueField="ProductId" Enabled="@( CurrentOrder.CategoryId > 0 )"
46+
ValueChanged="@( (int p) => ProductSelected(p) )">
47+
</TelerikDropDownList>
48+
49+
@* The last dropdown can use two-way binding, it does not need to filter subsequent data *@
50+
<TelerikDropDownList @bind-Value="@CurrentOrder.Quantity" Data="@Quantities" DefaultText="Select Quantity"
51+
Enabled="@( CurrentOrder.ProductId > 0 )">
52+
</TelerikDropDownList>
53+
54+
<TelerikButton Enabled="@( CurrentOrder.Quantity > 0 )" OnClick="@SendOrder">Send Order</TelerikButton>
55+
56+
@if (CurrentOrder.CategoryId > 0)
57+
{
58+
<h5>Order Summary</h5>
59+
@CurrentOrder.CategoryName
60+
<br />
61+
@CurrentOrder.ProductName
62+
<br />
63+
@CurrentOrder.Quantity
64+
}
65+
else if(!string.IsNullOrEmpty(orderStatusMessage))
66+
{
67+
<div class="alert alert-success">@orderStatusMessage</div>
68+
}
69+
70+
@code{
71+
// data sources
72+
List<Category> Categories { get; set; }
73+
List<Product> AllProducts { get; set; }
74+
List<Product> CurrentProducts { get; set; }
75+
List<int> Quantities { get; set; }
76+
// model
77+
Order CurrentOrder { get; set; } = new Order();
78+
79+
string orderStatusMessage { get; set; } // UI related for the sample
80+
81+
// generate data we will be using in this example
82+
protected override void OnInitialized()
83+
{
84+
base.OnInitialized();
85+
86+
Categories = Enumerable.Range(1, 6).Select(x => new Category
87+
{
88+
CategoryId = x,
89+
CategoryName = $"Category {x}"
90+
}).ToList();
91+
92+
AllProducts = Enumerable.Range(1, 50).Select(x => new Product
93+
{
94+
ProductId = x,
95+
ProductName = $"Product {x}",
96+
CategoryId = (int)Math.Ceiling((double)x % 7)
97+
}).ToList();
98+
}
99+
100+
//ValueChanged handlers - implementation of cascading dropdowns
101+
void CategorySelected(int category)
102+
{
103+
if(category == 0) // the default value - the user selected the default item == deselected the current item
104+
{
105+
//reset the "form" / process
106+
CurrentOrder = new Order();
107+
return;
108+
}
109+
110+
// cascade the selection by filtering the data for the next dropdown
111+
CurrentProducts = AllProducts.Where(p => p.CategoryId == category).ToList();
112+
113+
// get the selected model from the data source
114+
Category SelectedCategory = Categories.Where(c => c.CategoryId == category).First();
115+
116+
// business logic
117+
CurrentOrder.CategoryId = SelectedCategory.CategoryId;
118+
CurrentOrder.CategoryName = SelectedCategory.CategoryName;
119+
}
120+
121+
void ProductSelected(int product)
122+
{
123+
if(product == 0) // the default value - the user selected the default item == deselected the current item
124+
{
125+
//reset the "form" / process
126+
CurrentOrder.ProductId = product;
127+
CurrentOrder.ProductName = string.Empty;
128+
CurrentOrder.Quantity = 0;
129+
return;
130+
}
131+
132+
Random rnd = new Random();
133+
Quantities = Enumerable.Range(1, new Random().Next(5, 10)).ToList();
134+
135+
Product SelectedProduct = AllProducts.Where(p => p.ProductId == product).First();
136+
137+
CurrentOrder.ProductId = SelectedProduct.ProductId;
138+
CurrentOrder.ProductName = SelectedProduct.ProductName;
139+
}
140+
141+
// sample notification of success and reseting of the process, data classes
142+
async void SendOrder()
143+
{
144+
CurrentOrder = new Order();
145+
orderStatusMessage = "Thank you for your order!";
146+
await Task.Delay(2000);
147+
orderStatusMessage = "";
148+
StateHasChanged();
149+
}
150+
151+
public class Category
152+
{
153+
public int CategoryId { get; set; }
154+
public string CategoryName { get; set; }
155+
}
156+
157+
public class Product
158+
{
159+
public int CategoryId { get; set; }
160+
public int ProductId { get; set; }
161+
public string ProductName { get; set; }
162+
}
163+
164+
public class Order
165+
{
166+
public int CategoryId { get; set; }
167+
public string CategoryName { get; set; }
168+
public int ProductId { get; set; }
169+
public string ProductName { get; set; }
170+
public int Quantity { get; set; }
171+
}
172+
}
173+
````
174+

0 commit comments

Comments
 (0)