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.
Hitting the submit button displays your selection.
If JavaScript is Disabled
If JavaScript is disabled in the browser …
you get a message This site requires JavaScript
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.
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
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.
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.
I agree with Paul above. This is not unobtrusive at all and certainly not an example of best practices.
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?
I do not believe in javascript disabled,
If you are programming for javscript disabled, maybe also you wanna program for Lynx browser too?
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.
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.
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.
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….
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
You could also use the AjaxDropdown from http://awesome.codeplex.com
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.
I anyone want the code for this in VB – i have it available to download from http://www.mediafire.com
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
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?
@Oracularman — How does one save the values from the State dropdown. The sample code shows how.
Eu acho que vcs tao viajando na maionese
Why do I get URL undefined?
$('#ParentId').change(function () {
var URL = $('#DropdownFormId').data('childDdlListAction');
What is a good way to try to debug it?
@BusyBee
Try with 'childDdlListAction' all lowercase
The sample is just great. Do you have a new version for the latest jQuery version? Thank you.
Custom DropDown List Control,
http://www.kettic.com/…/dropdown_list.shtml
This is a great sample. It is simple and straight to the point. It is better than having it solve all problem.
Thanks Rick_Anderson ,
was helped,
has no one pointed out there is no sample code for the "StateList" controller action??
another good example here:
rohit-developer.blogspot.in/…/cascading-dropdown-list-in-aspnet-mvc.html
very simple and clean code sir
Can you tell me sir how can i show and hide some textboxes on dropdown selectedindexchange event in mvc5
vry nice article!
this may also help u :
http://www.mindstick.com/…/DropDownList%20in%20ASP%20NET%20MVC
Detailed one, great
how to bind from enum and some other tricks
http://www.advancesharp.com/…/mvc-dropdown-binding-best-ways
Fill on change of parent dropdown:
http://www.advancesharp.com/…/mvc-dropdownlistfor-fill-on-selection-change-of-another-dropdown