Cascading DropDownList in ASP.Net MVC


I have written a simple sample showing how to implement cascading drop down lists in ASP.Net MVC.   In this sample the user is presented with a list of countries. Once a country is selected, a new drop down list is appears showing the states in the selected country. You can download the sample here. Although there are a few simpler samples of implementing a cascading drop-down list in ASP.Net MVC, most of them mix JavaScript and markup (i.e. they are not unobtrusive), and they don’t work when deployed to IIS. Ideally you enhance functionality with JavaScript, you don’t require it. To keep this sample as simple as possible, it doesn’t implement the traditional server post back method used JavaScript is not available. Instead this sample shows best JavaScript/jQuery practices when using the jQuery.getJSON method to populate a drop-down list box. It is not meant to be a sample showing how to implement this functionality when JavaScript is not enabled. Implementing server postback to populate the ListBox when JavaScript is disabled is not difficult and not addressed in this sample.

1st

image

image

Hitting the submit button displays your selection.

image

If JavaScript is Disabled

If JavaScript is disabled in the browser …

disableJavaScript

you get a message This site requires JavaScript

image

That message is delivered with the HTML4  <noscript> element in the Views\Shared\_Layout.cshtml file.

    <noscript>
        <div>
            <h2>This site requires JavaScript</h2>
        </div>
    </noscript>

I’ve modified the Site.css file and set the main ID to not display.

#main {
    display: none;
    padding: 30px 30px 15px 30px;
 }

Browsers that have JavaScript enabled run Scripts\myReady.js, which shows the DOM element with ID main.

$(function () {
    $('#main').show();  
});

 

The Magic of jQuery

The IndexDDL action method creates a SelectList of countries, stores it in the ViewBag and passes it to the IndexDDL view.

public SelectList GetCountrySelectList() {

    var countries = Country.GetCountries();
    return new SelectList(countries.ToArray(),
                        "Code",
                        "Name");

}

public ActionResult IndexDDL() {

    ViewBag.Country = GetCountrySelectList();
    return View();
}

The IndexDDL view is shown below.

1IndexDDL

The Countries DropDownList has an ID CountriesID (shown in yellow highlight above), which enable the Scripts/countryState.js script to hook up changes in the country selection (yellow highlight below). The Scripts/countryState.js file is shown below.

$(function () {

    $('#StatesDivID').hide();
    $('#SubmitID').hide();

    $('#CountriesID').change(function () {
        var URL = $('#CountryStateFormID').data('stateListAction');
        $.getJSON(URL + '/' + $('#CountriesID').val(), function (data) {
            var items = '<option>Select a State</option>';
            $.each(data, function (i, state) {
                items += "<option value='" + state.Value + "'>" + state.Text + "</option>";
                // state.Value cannot contain ' character. We are OK because state.Value = cnt++;
            });
            $('#StatesID').html(items);
            $('#StatesDivID').show();

        });
    });

    $('#StatesID').change(function () {
        $('#SubmitID').show();
    });
});

The IndexDDL view stashes the URL to get the states associated with the selected country in the HTLM5 data dash attribute data-stateListAction . C# doesn’t allow a dash (-) in variable names, so we use underscore and Razor converts it to a dash character. The highlighted code below shows how we store and retrieve the URL used to get the states list.

@{
    ViewBag.Title = "Classic Cascading DDL";
}

@using (Html.BeginForm("IndexDDL", "Home", FormMethod.Post, 
    new { id = "CountryStateFormID", 
          data_stateListAction = @Url.Action("StateList") })) {
    <fieldset>
        <legend>Country/State</legend>
        @Html.DropDownList("Countries", ViewBag.Country as SelectList,
            "Select a Country", new { id = "CountriesID" })
        <div id="StatesDivID" >
            <label for="States">States</label>
            <select id="StatesID"  name="States"></select>
        </div>
        <p>
            <input type="submit" value="Submit" id="SubmitID" />
        </p>
    </fieldset>
}

<script src="@Url.Content("~/Scripts/countryState.js")"></script>

The Scripts/countryState.js script uses the CountryStateFormID to harvest the data-stateListAction attribute, which is the URL for the StateList action method in the home controller. The Scripts/countryState.js file is shown below.

$(function () {

    $('#StatesDivID').hide();
    $('#SubmitID').hide();

    $('#CountriesID').change(function () {
        var URL = $('#CountryStateFormID').data('stateListAction');
        $.getJSON(URL + '/' + $('#CountriesID').val(), function (data) {
            var items = '<option>Select a State</option>';
            $.each(data, function (i, state) {
                items += "<option value='" + state.Value + "'>" + state.Text + "</option>";
                // state.Value cannot contain ' character. We are OK because state.Value = cnt++;
            });
            $('#StatesID').html(items);
            $('#StatesDivID').show();

        });
    });

    $('#StatesID').change(function () {
        $('#SubmitID').show();
    });
});

The Index method is similar to the IndexDDL method, except the Index method doesn’t build  a SelectList of countries and pass it to the view via the ViewBag. The Index view is hooked up to the Scripts\GetCountry.js script to retrieve the list of countries.

For more information on working with the ASP.NET MVC DropDownList, see my sample Using the DropDownList and ListBox with ASP.NET MVC.

Rick.Anderson at Microsoft.com


Comments (29)

  1. Edmund says:

    Note that $.getJSON is an async call (uses a callback). If you have multiple dependent child select lists, use jAquery's $.ajax call with the async option set as false.

    This will allow proper population of multiple child select lists.

  2. Paul says:

    This is absolute nonsense, you take away the fact that the user can use the dropdown with javascript disabled? Just fallback to a normal submit button for each option.

  3. Bill says:

    I agree with Paul above. This is not unobtrusive at all and certainly not an example of best practices.

  4. BJ says:

    Easy there Paul.  One of the purposes of this post is to demonstrate how to use JavaScript as part of the solution.  If JavaScript is disabled then it defeats the purpose of the post.  Don't you think?

  5. Andrei Ignat says:

    I do not believe in javascript disabled,

    If you are programming for javscript disabled, maybe also you wanna program for Lynx browser too?

  6. nick says:

    Very good idea! Intranet application would make sense, or phone but I would agree that there are lame users that don't use javascript.

    I think, its 2% in USA.

  7. Paul says:

    Nothing to do with if a user has javascript enabled or not, in fact, a bad script could have a knock on effect which breaks functionality. You develop for the unknown, not for your own ideas about how users should behave. What if a new, popular but underpowered device came out which disallowed large scripts such as jQuery? (think watches)  This is neither best practices nor unobtrusive.You enhance functionality with javascript, not enable it.

  8. Edmund :Note that $.getJSON is an async call (uses a callback). If you have multiple dependent child select lists, use jAquery's $.ajax call with the async option set as false.

    Thanks for pointing that out.

    Paul :This is absolute nonsense, you take away the fact that the user can use the dropdown with javascript disabled?

    You're missing the point. If you can find a better sample of doing the JavaScript correctly, I'll delete this and point to it. Implementing server post back behavior without JavaScript is not difficult, and was not done to keep this sample as simple as possible.

    BJ: Andrei Ignat : Nik

    Thanks for your comments.

    Paul: See above comments. You write samples to explain how to do specific tasks, not as production code that meets everyones needs. My sample shows how to do the JavaScript correctly.

  9. Drogon says:

    Why not use json and templating if we're requiring javascript? It seems like the json approach would be cleaner and take the markup out of the javascript….

  10. Drogon: My approach doesn't require JavaScript, it's pretty easy to fallback to Server Postbacks when JavaScript is not available. I just left it out to keep the sample as simple as possible. Send methis sample done with JSON – but it should allow for server postback fallback with no JavaScript – Rick.Anderson at Microsoft.com

  11. Jeremy says:

    You could also use the AjaxDropdown from http://awesome.codeplex.com

  12. Jeremy: You could also use the AjaxDropdown. Shoot me my sample implemented with the codeplexAjaxDropdown  and I can add it to this blog link to your blog on it.

  13. Dnet78 says:

    I anyone want the code for this in VB – i have it available to download from http://www.mediafire.com

  14. Raphaël Désalbres says:

    Hello,

    Your article is good, however I prefer to use this plugin:

    weblogs.asp.net/…/cascadingdropdown-jquery-plugin-for-asp-net-mvc.aspx

    Raphaël

  15. Oracularman says:

    How does one save the values from the State dropdown or pass them to the ActionResult Method within the controller? I am unable to capture any values using the FormCollection formCollection object.  Anybody?

  16. @Oracularman   — How does one save the values from the State dropdown. The sample code shows how.

  17. Rico says:

    Eu acho que vcs tao viajando na maionese

  18. BusyBee says:

    Why do I get URL undefined?

       $('#ParentId').change(function () {

           var URL = $('#DropdownFormId').data('childDdlListAction');

    What is a good way to try to debug it?

  19. roger says:

    @BusyBee

    Try with 'childDdlListAction' all lowercase

  20. Cesar C says:

    The sample is just great. Do you have a new version for the latest jQuery version? Thank you.

  21. Tope says:

    This is a great sample. It is simple and straight to the point. It is better than having it solve all problem.

  22. upen says:

    Thanks  Rick_Anderson ,

    was helped,

  23. Jgaje says:

    has no one pointed out there is no sample code for the "StateList" controller action??

  24. Rajeshgajra19889 says:

    very simple and clean code sir

  25. Prerna Jain says:

    Can you tell me sir how can i show and hide some textboxes on dropdown selectedindexchange event in mvc5

Skip to main content