ASP.NET MVC–Cascading Dropdown Lists Tutorial–Part 5.1: Cascading using jQuery.ajax() ($.ajax() and DOM Objects)
- Part 1 – Defining the problem and the context
- Part 2 – Cascading using normal FORM post (Html.BeginForm helper)
- Part 3 – Cascading using Microsoft AJAX (Ajax.BeginForm helper)
- Part 4 – Cascading using FORM Hijaxing
- Part 5 – Cascading using jQuery.ajax():
- Part 5.1 – $.ajax() and DOM Objects
- Part 5.2 – $.ajax() and jQuery Templates
- Part 5.3 – $.ajax() and Knockout.js
- Part 6 – Creating a jQuery Cascade Select Plugin
Part 5.1: Cascading using jQuery.ajax() ($.ajax() and DOM Objects)
In this part we will use ASP.NET MVC to create an application that will act more like a JSON service than a Web application. For start let’s create a new controller called DropDownjQueryAjaxPostController:
public partial class DropDownjQueryAjaxPostController : Controller { private readonly IContinentRepository _continentRepository; private readonly ICountryRepository _countryRepository; private readonly ICityRepository _cityRepository; // If you are using Dependency Injection, you can delete the following constructor public DropDownjQueryAjaxPostController( ) : this( new ContinentRepository( ) , new CountryRepository( ) , new CityRepository( ) ) { } public DropDownjQueryAjaxPostController( IContinentRepository continentRepository , ICountryRepository countryRepository , ICityRepository cityRepository ) { this._continentRepository = continentRepository; this._countryRepository = countryRepository; this._cityRepository = cityRepository; } public virtual ViewResult Index( ) { return View( ); } }
Nothing unusual here. We set up repositories and the Index action. The unusual thing is that we return the Index view without any model and that the Index view is the only view we have:
@{ ViewBag.Title = "Index"; } <fieldset> <legend>Continents</legend> <select id='continents'> <option value=''>[Please select a continent]</option> </select> </fieldset> <fieldset> <legend>Countries</legend> <div id="countriesContainer"> <select id='countries' style='display: none;'> <option value=''>[Please select a country]</option> </select> <span id='noInfoCountries'>No information available </span> </div> </fieldset> <fieldset> <legend>Cities</legend> <div id="citiesContainer"> <table id='cities' style='display: none;'> <tr> <th> Name </th> <th> Population </th> </tr> </table> <span id='noInfoCities'>No information available </span> </div> </fieldset>
Let’s see what we have:
-
An empty continents dropdown list (we could fill the continents from the view but we’ll see another way)
-
An empty hidden countries dropdown list and a “No information available” span that will be visible if there is no continent selected
-
An empty hidden cities table and another “No information available” span that will be visible if there is no country selected
So the first thing that we have to do is to fill the continents dropdown list when the page loads:
<script type='text/javascript'> $(document).ready(function () { //Load the continents $.ajax({ url: '@Url.Action( MVC.CascadingDropDownLists.DropDownjQueryAjaxPost.GetContinents( ) )', type: 'GET', success: function (data) { var contients = $('#continents'); var domContinents = contients.get(0); // $('#id') != document.getElementById('id') //Empty the continents dropdown list for (var i = domContinents.options.length - 1; i > 0; i--) { domContinents.remove(i); } for (var i = 0; i < data.length; i++) { var item = data[i]; var continentOption = new Option(item.Name, item.Id); contients.append(continentOption); } } }); }); </script>
We use the jQuery.ajax () method (or $.ajax() for short) to perform a Ajax Get request on the GetContinents action. If the call succeds we clear the contents of the dropdownlist and fill it with the data received. Nothing to complicated, just javascript objects and method calls. The only odd thing is the continents and domContinents (see the comment in the code above).
Next we need to catch the change event for the continents dropdown list and perform another Ajax Get request to get the countries for the selected continent:
//Catch the continents change event $('#continents').live('change', function () { var countries = $('#countries'); var noInfo = $('#noInfoCountries'); var domCountries = countries.get(0); for (var i = domCountries.options.length - 1; i > 0; i--) { domCountries.remove(i); } $('#cities').hide(); $('#noInfoCities').show(); if ($('#continents option:selected').val() != '') { $.ajax({ url: '@Url.Action( MVC.CascadingDropDownLists.DropDownjQueryAjaxPost.GetCountries( ) )', data: { continentId: $('#continents option:selected').val() }, type: 'GET', success: function (data) { if (data.length > 0) { for (var i = 0; i < data.length; i++) { var item = data[i]; var countryOption = new Option(item.Name, item.Id); countries.append(countryOption); } noInfo.hide(); countries.show(); } else { countries.hide(); noInfo.show(); } } }); } else { countries.hide(); noInfo.show(); } });
When the continents dropdown list selection changes we empty the countries dropdown list. The request is only performed if there is a continent selected, otherwise the “No Information Available” span becomes visible. The span becomes visible also if there are no countries in the continent (for Antarctica).
Next we catch the countries dropdown list change event:
//Catch the countries change event $('#countries').live('change', function () { var cities = $('#cities'); var domCities = cities.get(0); for (var i = domCities.rows.length - 1; i > 0; i--) { domCities.deleteRow(i); } var noInfo = $('#noInfoCities'); if ($('#countries option:selected').val() != '') { $.ajax({ url: '@Url.Action( MVC.CascadingDropDownLists.DropDownjQueryAjaxPost.GetCities( ) )', data: { countryId: $('#countries option:selected').val() }, type: 'GET', success: function (data) { if (data.length > 0) { for (var i = 0; i < data.length; i++) { var item = data[i]; var lastRow = domCities.rows.length; var cityRow = domCities.insertRow(lastRow); var cityName = cityRow.insertCell(0); cityName.innerHTML = item.Name; var cityPopulation = cityRow.insertCell(1); cityPopulation.innerHTML = item.Population.toString(); cityPopulation.align = 'right'; } noInfo.hide(); cities.show(); } else { cities.hide(); noInfo.show(); } } }); } else { countries.hide(); noInfo.show(); } });
This is it. Not to complicated but there is some code to write.
See it in action
Cascading Dropdown Lists - jQuery.ajax()
There are some things that can be improved in this method:
-
Using the DOM objects is kind of ugly (adding and removing options and rows)
-
There are a lot of ifs to hide and show elements depending on selections
We will correct them in the next 2 parts
Download