ASP.NET MVC Cascading DropDownList with jQuery

Here a simple example of cascading drop down list in ASP.NET MVC with jQuery.

First you need models. I chosed to do this example using a Country and State dropdown, so I’m going to build to Models (Country and State) with a little bit of fake data.

Lets start with the Country Model and Fake Data

using System.Collections.Generic;
using System.Linq;

namespace CascadingDDLjQueryDemo.Models
{
    public class Country
    {
        public string CountryCode { get; set; }
        public string CountryName { get; set; }

        public static IQueryable GetCountries()
        {
            return new List
            {
                new Country {
                    CountryCode = "CA",
                    CountryName = "Canada"
                },
                new Country{
                    CountryCode = "US",
                    CountryName = "United-States"
                }
            }.AsQueryable();
        }
    }
}

And now the State Model and Fake Data

using System.Collections.Generic;
using System.Linq;

namespace CascadingDDLjQueryDemo.Models
{
    public class State
    {
        public string CountryCode { get; set; }
        public int StateID { get; set; }
        public string StateName { get; set; }

        public static IQueryable GetStates()
        {
            return new List
            {
                new State
                    {
                        CountryCode = "CA",
                        StateID=1,
                        StateName = "Ontario"
                    },
                new State
                    {
                        CountryCode = "CA",
                        StateID=2,
                        StateName = "Quebec"
                    },
                new State
                    {
                        CountryCode = "CA",
                        StateID=3,
                        StateName = "Nova Scotia"
                    },
                new State
                    {
                        CountryCode = "CA",
                        StateID=4,
                        StateName = "New Brunswick"
                    },
                new State
                    {
                        CountryCode = "CA",
                        StateID=5,
                        StateName = "Manitoba"
                    },
                new State
                    {
                        CountryCode = "CA",
                        StateID=6,
                        StateName = "British Columbia"
                    },
                new State
                    {
                        CountryCode = "CA",
                        StateID=7,
                        StateName = "Prince Edward Island"
                    },
                new State
                    {
                        CountryCode = "CA",
                        StateID=8,
                        StateName = "Saskatchewan"
                    },
                new State
                    {
                        CountryCode = "CA",
                        StateID=9,
                        StateName = "Alberta"
                    },
                new State
                    {
                        CountryCode = "CA",
                        StateID=10,
                        StateName = "Newfoundland and Labrador"
                    },
                new State
                    {
                        CountryCode = "US",
                        StateID=11,
                        StateName = "New-York"
                    },
                new State
                    {
                        CountryCode = "US",
                        StateID=12,
                        StateName = "California"
                    },
                new State
                    {
                        CountryCode = "US",
                        StateID=13,
                        StateName = "Washington"
                    },
                new State
                    {
                        CountryCode = "US",
                        StateID=14,
                        StateName = "Vermont"
                    }
            }.AsQueryable();
        }
    }
}

We can now add List methods in the controller. I chosed to return both Json and View so I could decide to make a page CountryList and use the same method.

using System.Linq;
using System.Web.Mvc;
using CascadingDDLjQueryDemo.Models;

namespace CascadingDDLjQueryDemo.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult CountryList()
        {
            IQueryable countries =
                Country.GetCountries();

            if(HttpContext.Request.IsAjaxRequest())
                return Json(new SelectList(
                                countries,
                                "CountryCode",
                                "CountryName")
                            );

            return View(countries);
        }

        public ActionResult StateList(string CountryCode)
        {
            IQueryable states = State.GetStates()
                .Where(x => x.CountryCode == CountryCode);

            if (HttpContext.Request.IsAjaxRequest())
                return Json(new SelectList(
                                states,
                                "StateID",
                                "StateName")
                            );

            return View(states);
        }
    }
}

And now we require Routes to access this data

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace CascadingDDLjQueryDemo
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode,
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "StatesList",
                "Home/States/List/{CountryCode}",
                new { controller = "Home", action = "StateList", CountryCode = "" }
            );

            routes.MapRoute(
                "CountriesList",
                "Home/Countries/List",
                new { controller = "Home", action = "CountryList" }
            );

            routes.MapRoute(
                "Default",
                "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = "" }
            );

        }

        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

The Javavascript

$(function() {
        $.getJSON("/Home/Countries/List", function(data) {
            var items = "";
            $.each(data, function(i, country) {
                items += "";
            });
            $("#Countries").html(items);
        });

        $("#Countries").change(function() {
            $.getJSON("/Home/States/List/" + $("#Countries > option:selected").attr("value"), function(data) {
                var items = "";
                $.each(data, function(i, state) {
                    items += "";
                });
                $("#States").html(items);
            });
        });
    });

And finally, the Index View.

ASP.NET MVC Cascading DropDownList using jQuery

You can find the source code here.

This entry was posted on Saturday, May 30th, 2009 at 6:50 pm and is filed under ASP.NET, C#.NET, Developement, LINQ, MVC. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

26 Responses to “ASP.NET MVC Cascading DropDownList with jQuery”

Scott June 15th, 2009 at 2:31 am

Nice article. One question though – Let’s assume that you have a submit button on the page and you want to use these values inside the posted controller, how do you go about getting these values as they don’t seem to be part of the FormsCollection that is getting passed back to my controller? Any assistance is greatly appreciated.

John Marsing June 22nd, 2009 at 10:19 am

Hello Michael.

Thank you for your sample I appreciate it. I have a VB application that needs one of these cascade drop down listboxes but I am have a problem getting it to work. I don’t know if you have time or not, but I was wondering if you could look at my application. The link is here…

http://cid-8f76d4da14a1b98a.skydrive.live.com/self.aspx/.Public/MVC/CascadeDDLVB.zip

I think the problem is that my Java script is not coded correctly, because it never fires my JSON methods in my controller. Maybe my Global.asax doesn’t have the routing correct???

thanks
John

Mike June 23rd, 2009 at 7:23 am

@scott: You should have the results in the FormsCollection, try some debugging! In any case I’ll make a little demo of this and publish it so you can find out where’s your problem!

Kyle Bailey July 19th, 2009 at 2:57 am

Mike

I’m having the same problem as Scott. I wrappe your control in a form with a submit button but the results are not being sent back to the from collection

Manuel Gomez July 21st, 2009 at 1:05 pm

Great post!!!

Thanks…

Mike July 22nd, 2009 at 11:07 am

@SCOTT & @KYLE: I’ve updated the source code with a submit button. Have fun :)

Vik September 2nd, 2009 at 5:08 pm

Hi Mike,
Thanks for this post and for the updated code with the submit button. Could you a little more on it? I’m trying to retain the selected values for country and state in the drop down lists after hitting the submit button but I’m not sure how to do this. Would greatly appreciate your insight on this.
thanks
Vik

Miroslav Ninkovi September 15th, 2009 at 4:16 am

Hallo Mike,
I really like you post. There is one thing that is bothering me and that is hardcoding url’s in jquery:

$.getJSON(“/Home/Countries/List”…)

When working with links and forms it is recommended to use helper methods like Html.ActionLink, Html.BeginForm so in case you change the routes you don’t have to bother to change anything.
I mean, what if in some point of time you want to change that MyHome is mapped to HomeController instead of Home?
How would you solve this problem?

teatime September 17th, 2009 at 7:01 am

Great post, have found it very useful!

Any chance you can suggest a simple / efficient way of having the lists loaded and Country / State selected if there are values already chosen? The change event doesn’t seem to fire until a user actually selects an item

Cheers

Mike September 21st, 2009 at 3:50 pm

@Miroslav Ninkovi: On the server side I usually use HTML Helpers for that, but for the AJAX calls I’ve always hard coded the route. Also, I usually name all my routes in the Global.asax instead of using the usual Controller/Action route. I’ve never encountered any problems this way, but I’d be very interested in hearing what others do about this.

paul mumgai October 2nd, 2009 at 6:13 am

Thank you for sharing this cool story :-)

Chris October 15th, 2009 at 4:30 pm

Thanks for this post Mike. To help out everyone I posted a class with (most) the countries coded up in the collection. Anyone is welcome to download it from my blog.

Chris

NVHien December 30th, 2009 at 12:59 pm

Instead of configure router, i use $.ajax() function to fire controller action.

$(document).ready(function() {
$.getJSON(“/Cascading/CountryList”, function(data) {
var items = “———————”;
$.each(data, function(i, country) {
items += “” + country.Text + “”;
});
$(“#Countries”).html(items);
});

$(“#Countries”).change(function() {
var countryId = $(‘#Countries’).val();
$.ajax({
url: ‘/Cascading/StateList/’,
type: ‘POST’,
dataType: ‘json’,
data: { CountryCode: countryId },
success: function(data) {
var items = “———————”;
$.each(data, function(i, state) {
items += “” + state.Text + “”;
});
$(“#States”).html(items);
}
});
});

});

marco February 18th, 2010 at 12:56 pm

Hello ,
thanks for the really useful code you brought us.
I’ve managed to use it in my “Create” viewform and the data is correctly saved into my database. I would love to have some help tough , for my “Edit” View , cause i can’t really make the cascading dropdowns get the value i pass from my dbcontext.table in the controller. Any idea on how to set the values of the 2 dropdowns ?

Thanks , and sorry my bad english.

ranjith February 22nd, 2010 at 8:32 pm

How to Edit or Update these cascading dropdowns.

Prashant July 14th, 2010 at 10:01 am

Hi,
I like your post.
This is exact feature that i am looking for.
I need a button on page and selected values in DDL should get access in controller side.
could you please send me update code.

Thanks,
Prashant

byrm January 28th, 2011 at 3:45 am

thanks for article. but this application did not work on entity framework entities. for example List (Product comes from EF.)
json result is coming null.

# $.getJSON(“/Home/States/List/” + $(“#Countries > option:selected”).attr(“value”), function(data) {
# this did not works well

Shashikant February 15th, 2011 at 9:20 am

I tried the code as replica but when I load the page my country dropdown has not values

Davide May 20th, 2011 at 11:04 am

Hi Mike your solution doesn’t work with VS2010 fx 3.5 / 4.0.

I do not know why.

Svat_ May 30th, 2011 at 5:19 pm

Hi, I have the same issue. Both of dropdowns are empty. Does any bode solve this issue? Please provide solution. Thanks in advance!

Ulmstead June 3rd, 2011 at 8:41 am

To make this work with the latest MVC/VS add JsonRequestBehavior.AllowGet param value to the Json() method.

See http://forums.asp.net/t/1483387.aspx

ACECLASSIC August 8th, 2011 at 6:33 am

Thank you mike for the code.

I am using Code First EF and it worked fine. The only hiccup with the code was JsonRequestBehavior.AllowGet(). This was the only link missing to get the JSON results.

I have countries and states being pulled out of the DB and populating the drop down.

Ryan September 6th, 2011 at 1:02 am

Lots of things, such as implementing nested lists, must be implemented with JavaScript. What if Java Script is disabled?! seems that ASP.NET MVC has sever problems!!

Mike September 29th, 2011 at 4:16 pm

If JavaScript is disable you are very limited on the web… besides the JavaScript is merely an enhancement, any good / production ready solution should be non-obstructive JavaScript. (This has nothing to do with ASP.NET MVC)

Christian November 9th, 2011 at 3:38 pm

Hi
Great tutorial! I tried to implement it to my project but it dosent seem to work… The dropdowns dont get data. The actionresult dosent even get called. What could I have i forgot?

Keivan Mousavi March 12th, 2012 at 8:08 am

Tanx My Friend

Leave a Reply