Cascading DropDownList in ASP.NET MVC

In this blog post you will learn how to create cascading DropDownList in ASP.NET MVC. I will take you through step by step approach so, let’s begin.

Case Study: I am going to create two DDLs (State and District). First DDL will let you pick state and when you pick state, it will make a parameterized JSON call using jQuery that will return matching set of districts that will be populated to second DDL. I will also show how to use proper validations with each control. Here is the animated screen that we are going to create.



Now, let’s follow the steps.

Step 1

At very first, we need a model class that defines properties for storing data.

    public class ApplicationForm
    {
        public string Name { get; set; }
        public string State { get; set; }
        public string District { get; set; }
    }

Step 2

Now, we need an initial controller that will return an Index view by packing list of states in ViewBag.StateName.

    public ActionResult Index()
    {
        List<SelectListItem> state = new List<SelectListItem>();
        state.Add(new SelectListItem { Text = "Bihar", Value = "Bihar" });
        state.Add(new SelectListItem { Text = "Jharkhand", Value = "Jharkhand" });
        ViewBag.StateName = new SelectList(state, "Value", "Text");

        return View();
    }

In above controller we have a List<SelectListItem> containing states attached to ViewBag.StateName. We could get list of states form database using Linq query or something and pack it to ViewBag.StateName, well let’s go with in-memory data.

Step 3

Once we have controller we can add its view and start creating a Razor form.

@Html.ValidationSummary("Please correct the errors and try again.")

@using (Html.BeginForm())
{
    <fieldset>
        <legend>DropDownList</legend>
        @Html.Label("Name")
        @Html.TextBox("Name")
        @Html.ValidationMessage("Name", "*")

        @Html.Label("State")
        @Html.DropDownList("State", ViewBag.StateName as SelectList, "Select a State", new { id = "State" })
        @Html.ValidationMessage("State", "*")

        @Html.Label("District")
        <select id="District" name="District"></select>
        @Html.ValidationMessage("District", "*")

        <p>
            <input type="submit" value="Create" id="SubmitId" />
        </p>
    </fieldset>
}

You can see I have added proper labels and validation fields with each input controls (two DropDownList and one TextBox) and also a validation summery at the top. Notice, I have used <select id=”District”….> which is HTML instead of Razor helper this is because when we make JSON call using jQuery will return HTML markup of pre-populated option tag. Now, let’s add jQuery code in the above view page.

Step 4

Here is the jQuery code making JSON call to DDL named controller’s DistrictList method with a parameter (which is selected state name). DistrictList method will returns JSON data. With the returned JSON data we are building <option> tag HTML markup and attaching this HTML markup to ‘District’ which is DOM control.

@Scripts.Render("~/bundles/jquery")
<script type="text/jscript">
    $(function () {
        $('#State').change(function () {
            $.getJSON('/DDL/DistrictList/' + $('#State').val(), function (data) {
                var items = '<option>Select a District</option>';
                $.each(data, function (i, district) {
                    items += "<option value='" + district.Value + "'>" + district.Text + "</option>";
                });
                $('#District').html(items);
            });
        });
    });
</script>

Please make sure you are using jQuery library references before the <script> tag.

Step 5

In above jQuery code we are making a JSON call to DDL named controller’s DistrictList method with a parameter. Here is the DistrictList method code which will return JSON data.

    public JsonResult DistrictList(string Id)
    {
        var district = from s in District.GetDistrict()
                        where s.StateName == Id
                        select s;

        return Json(new SelectList(district.ToArray(), "StateName", "DistrictName"), JsonRequestBehavior.AllowGet);
    }

Please note, DistrictList method will accept an ‘Id’ (it should be 'Id' always) parameter of string type sent by the jQuery JSON call. Inside the method, I am using ‘Id’ parameter in linq query to get list of matching districts and conceptually, in the list of district data there should be a state field. Also note, in the linq query I am making a method call District.GetDistrict().

Step 6

In above District.GetDistrict() method call, District is a model which has a GetDistrict() method. And I am using GetDistrict() method in linq query, so this method should be of type IQueryable. Here is the model code.

    public class District
    {
        public string StateName { get; set; }
        public string DistrictName { get; set; }

        public static IQueryable<District> GetDistrict()
        {
            return new List<District>
            {
                new District { StateName = "Bihar", DistrictName = "Motihari" },
                new District { StateName = "Bihar", DistrictName = "Muzaffarpur" },
                new District { StateName = "Bihar", DistrictName = "Patna" },
                new District { StateName = "Jharkhand", DistrictName = "Bokaro" },
                new District { StateName = "Jharkhand", DistrictName = "Ranchi" },
            }.AsQueryable();
        }
    }

Step 7

You can run the application here because cascading dropdownlist is ready now. I am going to do some validation works when user clicks the submit button. So, I will add another action result of POST version.

    [HttpPost]
    public ActionResult Index(ApplicationForm formdata)
    {
        if (formdata.Name == null)
        {
            ModelState.AddModelError("Name", "Name is required field.");
        }
        if (formdata.State == null)
        {
            ModelState.AddModelError("State", "State is required field.");
        }
        if (formdata.District == null)
        {
            ModelState.AddModelError("District", "District is required field.");
        }

        if (!ModelState.IsValid)
        {
            //Populate the list again
            List<SelectListItem> state = new List<SelectListItem>();
            state.Add(new SelectListItem { Text = "Bihar", Value = "Bihar" });
            state.Add(new SelectListItem { Text = "Jharkhand", Value = "Jharkhand" });
            ViewBag.StateName = new SelectList(state, "Value", "Text");

            return View("Index");
        }

        //TODO: Database Insertion
           
        return RedirectToAction("Index", "Home");
    }

And, this action result will accept ApplicationForm model data and based on posted data will do validations. If a validation error occurs, the action method calls the AddModelError method to add the error to the associated ModelState object. The AddModelError method accepts the name of the associated property and the error message to display. After the action method executes the validation rules, it uses the IsValid property of the ModelStateDictionary collection to determine whether the resulting data complies with the model.

So, this is all. If you wish to see the complete codes, use the links given below.

Model: ApplicationForm.cs | Controller: DDLController.cs | View: Index.cshtml

Hope this helps.

Comments

  1. Trust me , i used to read your each and every article, in fact...i had gone through your entire website after i found it first time..
    :)

    Great work and keep doing it.

    ReplyDelete
    Replies
    1. Hi, it's very nice example. well, Do you have any idea why does the Dropdown Change Envent not fire at all? it never goes to the following section

      @section scripts
      {
      */// here is the script***
      }

      Delete
    2. Hi abhimanyu, the problem is that while changing states from drawdown list it doesn't go to script section at all. do you have any idea?

      Delete
    3. This code is working fine.......

      $.getJSON('/DDL/DistrictList/' + $('#State').val(), function (data) {

      in above code,i want to pass more than one parameter then how can i do this?

      Delete
    4. Dear Anonymous

      this is problem related to Jquery files not getting included .I was facing the same problem so i doubt Jquery files not getting included in @Scripts.Render("~/bundles/jquery") . then i simply created new MVC 4 project with Internet option instead of empty . and its get solved .

      Delete
  2. 100% positiv for a great job. I was looking for some like this for a long time. Work perfect for me :) THX once again

    ReplyDelete
  3. There is no ViewData item of type 'IEnumerable' that has the key 'State'.
    this is the error i got when i try the example

    this line

    @Html.DropDownList("State", ViewBag.StateName as SelectList, "Select a State", new { id = "State" })
    thanks in advance

    ReplyDelete
    Replies
    1. In Controller Assign the Values to the View Bag Like This

      ViewBag.StateName = new SelectList(state, "Value", "Text");

      Delete
  4. Thank You for your article. I have MS SQL (2010) db, each state table (statePcode -PK; stateName) and district table (districtPcode-PK; districtName; statePcode=FK).

    I want when I select state it should show the relevant district under that state, using Pcode relationship in SQL database.

    Kindly help any one, I using ASP.Net MVC4 using LinQ.

    Thank You
    Regards
    Elil

    ReplyDelete
  5. if i want to bind data from database then what can i do, actually i want to call city on the click of state and i make the proper procedure and table for it but i dont know how i call this plz help me i am new on mvc...
    i work on single dropdown but i have problem when i call the second dropdown on click of first.....

    ReplyDelete
  6. i am new on mvc, i can call the single dropdown but i have problem when i m calling the second dropdown on the click of first dropdown and speclly when i bind the dropdown from database...
    plz help me....

    ReplyDelete
  7. Hi abhimanyu,
    it's very nice example. i am trying to implement it but the problem is that while changing states from drawdown list it doesn't go to script section at all. do you have any idea?
    Do you have any idea why does the Dropdown Change Envent not fire at all?

    please reply asap . thanks in advance

    ReplyDelete
  8. Can we done this work without use of java script.

    ReplyDelete
  9. how to bind dropdown without using json ? there is any anoother way ?

    ReplyDelete

Post a Comment

Popular posts from this blog

Migrating database from ASP.NET Identity to ASP.NET Core Identity

Customize User's Profile in ASP.NET Identity System