Skip to content

Commit 04334aa

Browse files
kb(dropdowns): cascading multiselect
1 parent e086d85 commit 04334aa

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

knowledge-base/dropdown-cascading.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,4 +309,156 @@ else if (!string.IsNullOrEmpty(orderStatusMessage))
309309
}
310310
}
311311
````
312+
````MultiSelect
313+
@using System.Collections.ObjectModel
314+
315+
<TelerikMultiSelect Value="@CurrentOrder.Categories" Data="@Categories" Placeholder="Select Categories"
316+
TextField="CategoryName" ValueField="CategoryId" Filterable="true"
317+
ValueChanged="@( (List<int> c) => CategorySelected(c) )">
318+
</TelerikMultiSelect>
319+
320+
<TelerikMultiSelect Value="@CurrentOrder.Products" Data="@CurrentProducts" Placeholder="Select Products" Filterable="true"
321+
TextField="ProductName" ValueField="ProductId" Enabled="@( CurrentOrder.Categories.Count > 0 )"
322+
ValueChanged="@( (List<int> p) => ProductSelected(p) )">
323+
</TelerikMultiSelect>
324+
325+
@* This sample has only two dropdowns as even dummy data becomes rather long for a multiselect scenario, even for a demo
326+
The last item could use @bind-Value instead of a handler, this just showcases the main concept. *@
327+
328+
<TelerikButton Enabled="@( CurrentOrder.Products.Count > 0 )" OnClick="@SendOrder">Send Order</TelerikButton>
329+
330+
@if (CurrentOrder.Products.Count > 0)
331+
{
332+
<h5>Order Summary</h5>
333+
<ul>
334+
@foreach (var item in CurrentOrder.ChosenProducts)
335+
{
336+
<li>@item.ProductName from category @item.CategoryId</li>
337+
}
338+
</ul>
339+
}
340+
else if (!string.IsNullOrEmpty(orderStatusMessage))
341+
{
342+
<div class="alert alert-success">@orderStatusMessage</div>
343+
}
344+
345+
@code{
346+
// data sources
347+
List<Category> Categories { get; set; }
348+
List<Product> AllProducts { get; set; }
349+
ObservableCollection<Product> CurrentProducts { get; set; } = new ObservableCollection<Product>();
350+
// model
351+
Order CurrentOrder { get; set; } = new Order();
352+
353+
string orderStatusMessage { get; set; } // UI related for the sample
354+
355+
// generate data we will be using in this example
356+
protected override void OnInitialized()
357+
{
358+
base.OnInitialized();
359+
360+
Categories = Enumerable.Range(1, 6).Select(x => new Category
361+
{
362+
CategoryId = x,
363+
CategoryName = $"Category {x}"
364+
}).ToList();
365+
366+
AllProducts = Enumerable.Range(1, 50).Select(x => new Product
367+
{
368+
ProductId = x,
369+
ProductName = $"Product {x}",
370+
CategoryId = (int)Math.Ceiling((double)x % 7)
371+
}).ToList();
372+
}
373+
374+
//ValueChanged handlers - implementation of cascading dropdowns
375+
void CategorySelected(List<int> categories)
376+
{
377+
if (categories.Count == 0) // the user deselected all
378+
{
379+
//reset the "form" / process
380+
CurrentOrder = new Order();
381+
return;
382+
}
383+
384+
// cascade the selection by filtering the data for the next dropdown
385+
CurrentProducts.Clear();
386+
foreach (var item in categories)
387+
{
388+
var productForCategory = AllProducts.Where(p => p.CategoryId == item);
389+
foreach (var p in productForCategory)
390+
{
391+
CurrentProducts.Add(p);
392+
}
393+
}
394+
CurrentProducts.OrderBy(p => p.ProductId);
395+
396+
397+
// get the selected models from the data source and use them
398+
CurrentOrder.Categories.Clear();
399+
CurrentOrder.ChosenCategories.Clear();
400+
foreach (var item in categories)
401+
{
402+
Category SelectedCategory = Categories.Where(c => c.CategoryId == item).First();
403+
CurrentOrder.Categories.Add(item);
404+
// business logic
405+
CurrentOrder.ChosenCategories.Add(SelectedCategory);
406+
}
407+
}
408+
409+
void ProductSelected(List<int> products)
410+
{
411+
if (products.Count == 0) // the user deselected all
412+
{
413+
//reset the "form" / process
414+
CurrentOrder.Products = new List<int>();
415+
CurrentOrder.ChosenProducts = new List<Product>();
416+
return;
417+
}
418+
419+
420+
// get the selected models from the data source and use them
421+
CurrentOrder.Products.Clear();
422+
CurrentOrder.ChosenProducts.Clear();
423+
foreach (var item in products)
424+
{
425+
Product SelectedProduct = AllProducts.Where(p => p.ProductId == item).First();
426+
CurrentOrder.Products.Add(item);
427+
// business logic
428+
CurrentOrder.ChosenProducts.Add(SelectedProduct);
429+
}
430+
}
431+
432+
// sample notification of success and resetting of the process, data classes
433+
async void SendOrder()
434+
{
435+
CurrentOrder = new Order();
436+
orderStatusMessage = "Thank you for your order!";
437+
await Task.Delay(2000);
438+
orderStatusMessage = "";
439+
StateHasChanged();
440+
}
441+
442+
public class Category
443+
{
444+
public int CategoryId { get; set; }
445+
public string CategoryName { get; set; }
446+
}
447+
448+
public class Product
449+
{
450+
public int CategoryId { get; set; }
451+
public int ProductId { get; set; }
452+
public string ProductName { get; set; }
453+
}
454+
455+
public class Order
456+
{
457+
public List<int> Categories { get; set; } = new List<int>();
458+
public List<int> Products { get; set; } = new List<int>();
459+
public List<Category> ChosenCategories { get; set; } = new List<Category>();
460+
public List<Product> ChosenProducts { get; set; } = new List<Product>();
461+
}
462+
}
463+
````
312464

0 commit comments

Comments
 (0)