Simple Implementation of MVC Cascading Ajax Drop Down
Lets start! Lets say you have the following structure below.
You need to have models for each of them
Now you need a controller to perform all of the operations, Lets call it CascadingDropDown.cs, we need 3 Actions Results one for the Index which will Load the page and populate the Category DropDown, Select Category to populate Sub Category Drop Down and Select Sub Category to populate Products Drop Down. If you notice the name might be confusing that is because it is named after an Action Result not action to perform, which means what Action was invoked for this to happen. Below is a sample code.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApplication1.Controllers { using Models; public class CascadingDropDownController : Controller { public ActionResult Index() { ProductCatalog productCatalog = new ProductCatalog(); productCatalog.Categories = ProductCatalog.GetCategories(); return View(productCatalog); } [HttpPost] public ActionResult SelectCategory(int? selectedCategoryId) { ProductCatalog productCatalog = new ProductCatalog(); productCatalog.SubCategories = new List<SubCategory>(); if (selectedCategoryId.HasValue) { productCatalog.SubCategories = (from s in ProductCatalog.GetSubCategories() where s.CategoryId == selectedCategoryId orderby s.Name select s).ToList(); } return PartialView("SubCategoriesUserControl", productCatalog); } [HttpPost] public ActionResult SelectSubCategory(int? selectedSubCategoryId) { ProductCatalog productCatalog = new ProductCatalog(); productCatalog.Products = new List<Product>(); if (selectedSubCategoryId.HasValue) { productCatalog.Products = (from s in ProductCatalog.GetProducts() where s.SubCategoryId == selectedSubCategoryId orderby s.Name select s).ToList(); } return PartialView("ProductsUserControl", productCatalog); } } }Take note we use partial view on the SelectCategory and SelectSubCategory as we will send a partial view to the response. While on the Index we need the full rendering to the response. Now you have your controller we need to create those views. We need 1 view for Index and 3 partial views for the 3 dropdowns.
Now lets create the Index view, all you have to do is to right-click on the Index method on your controller then you can start coding. This view will display all of the dropdowns.
Index.cshtml
@model MvcApplication1.Models.ProductCatalog @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } <table cellpadding="0" cellspacing="4" border="0"> <tr> <td>Category </td> <td> :</td> <td>@Html.Partial("CategoriesUserControl", Model)</td> </tr> <tr> <td>Sub - Category </td> <td> :</td> <td><div id="SubCategories">@Html.Partial("SubCategoriesUserControl", Model)</div></td> </tr> <tr> <td>Products </td> <td> :</td> <td><div id="Products">@Html.Partial("ProductsUserControl", Model)</div></td> </tr> </table>Now lets create partial views and for those who does not know how just right-click on the parent folder where your Index view is and Select Add -> View then tick the “create as a partial view”.
Now for the codes:
CategoriesUserControl.cshtml
@model MvcApplication1.Models.ProductCatalog @using (Ajax.BeginForm("SelectCategory", "CascadingDropDown", new AjaxOptions { UpdateTargetId = "SubCategories" })) { @Html.DropDownListFor( m => m.SelectedCategoryId, new SelectList(Model.Categories, "Id", "Name"), string.Empty ) } <script type="text/javascript"> $('#SelectedCategoryId').change(function () { $(this).parents('form').submit(); }); </script>
SubCategoriesUserControl.cshtml
@model MvcApplication1.Models.ProductCatalog @if (Model.SubCategories != null && Model.SubCategories.Count() > 0) { using (Ajax.BeginForm("SelectSubCategory", "CascadingDropDown", new AjaxOptions { UpdateTargetId = "Products" })) { @Html.HiddenFor(m => m.SelectedCategoryId) @Html.DropDownListFor( m => m.SelectedSubCategoryId, new SelectList(Model.SubCategories, "Id", "Name"), string.Empty ) } } <script type="text/javascript"> $('#SelectedSubCategoryId').change(function () { $(this).parents('form').submit(); }); </script>
ProductsUserControl.cshtml
@model MvcApplication1.Models.ProductCatalog @if (Model.Products != null && Model.Products.Count() > 0) { @Html.DropDownList( "Products", new SelectList(Model.Products, "Id", "Name"), string.Empty ) }If you notice instead of Html.BeginForm we use Ajax.BeginForm using the parameters below.
- actionName will be name of your method in your controller
- controllerName will be theame of your controller
- AjaxOptions as the name says AjaxOptions, at this point we only need the UpdateTargetId which we defined as <div> in the index.cshtml file.
Also on your _Layout.cshtml add this on the header if you haven’t done it yet
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>Note : If you are using ASP.Net MVC3 then by default it uses unobtrusive jquery so you need to remove all MicrosoftAjax scripts and use only those two above otherwise the onchange event will open a new page instead of partially rendering it.
Note : If you are using Telerik MVC Controls then you only need the unobtrusive ajax the other script is already referenced by default if you are using Telerik.
Make sure also on your web.config you have the following lines.<add key="ClientValidationEnabled" value="true"/> <add key="UnobtrusiveJavaScriptEnabled" value="true"/>At this point you have done everything you need and your ready to roll.
Thank you Shubham for a sublime, descriptive tutorial about MVC cascading AJAX drop down. It will help me a lot to understand exactly how should I work on it.
ReplyDeleteCustom Software Development India