top button
Flag Notify
    Connect to us
      Site Registration

Site Registration

Cascading DropDownLists Using "Eager Loading" On Client Side

+3 votes
342 views

One of my earlier articles (Creating Cascading DropDownLists using ASP.NET MVC 4 and jQuery) shows how to create cascading DropDownLists by making Ajax calls to the MVC action methods. While that approach is quite common and popular recently a reader asked whether something similar can be done without making any Ajax calls. If you want to implement cascading dropdownlists purely on client side then you will need to "eagerly load" all the data needed by them at the time of loading the page. This data can be stored in a hidden field and used as and when needed. Obviously this technique is not suitable for huge amount of data since everything is loaded at once on the client side. However, if the data is small and you understand the implications of loading it in advance here is how you can accomplish the task...

As an example we will use the same Country - Cities example. The entity data model for Countries and Cities table is shown below:

image

To hold the data that is to be sent to the client we create a POCO as shown below:

public class CountryCity
{
    public string Country { get; set; }
    public List<string> Cities { get; set; }
}

The CountryCity class has Country property that holds a CountryName from the database and the Cities property holds a List of CityName values. As mentioned earlier the data will be sent to the client in the form of a hidden form field. To store data in the hidden field we use JSON format. The code that does this job goes inside the Index action method and is shown below:

public ActionResult Index()
{
    LocationsDbEntities db = new LocationsDbEntities();
    var query = from c in db.Countries
                orderby c.CountryName ascending
                select new { 
                  CountryName = c.CountryName, 
                  Cities = c.Cities.ToList() };

    List<CountryCity> finalData = new List<CountryCity>();
    foreach (var country in query)
    {
        CountryCity obj = new CountryCity();
        obj.Country = country.CountryName;
        obj.Cities = new List<string>();
        foreach (var city in country.Cities)
        {
            obj.Cities.Add(city.CityName);
        }
        finalData.Add(obj);
    }
    string jsonData = JsonConvert.SerializeObject(finalData);
    ViewBag.LocationData = jsonData;
    return View();
}

The above code selects all the countries and their cities in an anonymous type using LINQ to Entities query. It then iterates through the results and forms a List of CountryCity objects. Once the whole List is formed it serializes that data into a string using Json.NET component. The SerializeObject() method of the JsonConvert class does that job. This string will hold the data in JSON format. This JSON data is then passed to the view using LocationData ViewBag property. A sample JSON data after serialization is shown below:

[
 {"Country":"USA",
  "Cities":["Redmond","Seattle"]},
 {"Country":"UK",
  "Cities":["London"]}
 {"Country":"India",
  "Cities":["Bangalore","Delhi"]}
]

The Index view that stores the LocationData ViewBag property into a hidden form field is shown below:

<form action="/home/processform" method="post">
    <input type="hidden" 
      id="locationdata" 
      name="locationdata" 
      value="@ViewBag.LocationData" />
    <select id="country" name="country"></select>
    <br /><br />
    <select id="city" name="city"></select>
    <br /><br />
    <input type="submit" value="Submit" />
</form>

As you can see the JSON data is stored in locationdata hidden form field. You will need to access this data for displaying it in the country and state dropdownlists. The jQuery code that does that is shown below:

<script type="text/javascript">
    var locationData;
    $(document).ready(function () {
        locationData = JSON.parse($("#locationdata").val());
        for (var i = 0; i < locationData.length;i++)
        {
            $("#country").append("<option>" + 
                          locationData[i].Country + 
                          "</option>");
        }
        $("#country").change(function () {
            var selectedCountry = $("#country").val();
            for (var i = 0 ; i < locationData.length; i++)
            {
                if(locationData[i].Country==selectedCountry)
                {
                    $("#city").empty();
                    for(var j=0;j<locationData[i].Cities.length;j++)
                    {
                        $("#city").append("<option>" + 
                                   locationData[i].Cities[j] + 
                                   "</option>");
                    }
                    return;
                }
            }
        });
    });
</script>

The above jQuery code declares a global variable - locationData - for storing the location data. The ready() function reads the hidden form field value and parses it into a JavaScript object using JSON.parse() method. A for loop then iterates through the locationData array and adds entries to the country dropdownlist using append() method.

The change() method wires the change event handler for the country dropdownlist. The change event handler iterates through the locationData array and finds the country matching the selection in the country dropdownlist. The code then retrieves cities for that country and populates the city dropdownlist.

That's it! Run the Index view and test whether it works as expected.

posted Nov 9, 2016 by Shivaranjini

  Promote This Article
Facebook Share Button Twitter Share Button LinkedIn Share Button


Related Articles

Sometimes you need to display DropDownLists in your ASP.NET MVC views such that values in one DropDownList are dependent on the value selected in another DropDownList. The most common example of such a functionality is countries and states DropDownLists where based on a selected country you need to populate the states DropDownList. This article shows how such a cascading DropDownLists can be developed using ASP.NET MVC and jQuery.

Have a look at the following figure that shows two DropDownLists:

image

As you can see the country DropDownList contains a list of countries along with the first entry of "Please select". Upon selecting a country the states DropDownList displays the states belonging to the selected country. When the page is loaded the country DropDownList has "Please select" entry selected and states DropDownList is disabled. Upon selecting a country the states DropDownList is enabled so that state selection can be made. Clicking on the Submit button submits the form to an action method for further processing.

Begin by creating a new ASP.NET MVC4 project based on empty project template. Add Scripts folder to the project and place jQuery library into it. Then add HomeController to the Controllers folder. In a real world scenario you will get countries and states from a database. Here, for the sake of simplicity, we will use some hardcoded country and state values.

Now add the following action method to the HomeController:

public ActionResult Index()
{
  List<string> items = new List<string>();
  items.Add("Please select");
  items.Add("USA");
  items.Add("UK");
  items.Add("India");
  SelectList countries = new SelectList(items);
  ViewData["countries"] = countries;
  return View();
}

The above code shows Index() action method. Inside the Index() method a generic List of strings is created to hold country names and a few countries are added to it. The DropDownList HTML helper of ASP.NET MVC requires its data in the form of SelectList object. Hence a SelectList is created based on the countries List. The SelectList object is passed to the view using countries ViewData variable.

Next, add another action method to the HomeController as shown below:

public JsonResult GetStates(string country)
{
  List<string> states = new List<string>();
  switch (country)
  {
    case "USA":
      states.Add("California");
      states.Add("Florida");
      states.Add("Ohio");
      break;
    case "UK":
      //add UK states here
      break;
    case "India":
      //add India states hete
      break;
  }
  return Json(states);
}

As you can see the GetStates() action method accepts a string parameter named country and returns JsonResult. The GetStates() returns JsonResult because this method will be called using jQuery and states information is to be returned as JSON data. The GetStates() method contains a simple switch statement that adds a few states to states List based on the country value. Finally, the states generic List is returned to the caller using Json() method. The Json() method converts any .NET object into its JSON equivalent.

Now, add Index view to the Views folder and key-in the following markup to it:

<% using(Html.BeginForm("ProcessForm","Home",FormMethod.Post)){ %>
<div>Select Country :</div>
<%= Html.DropDownList("country", ViewData["countries"] as SelectList)%>
<br /><br />
<div>Select States :</div>
<select id="state"></select>
<br /><br />
<input type="submit" value="Submit" />
<%} %>

The Index view consists of a <form> that houses two DropDownLists. The country DropDownList is rendered using DropDownList HTML helper. The first parameter of the DropDownList() helper is the name of the DropDownList and the second parameter is the SelectList object containing DropDownList values. The second DropDownList is added as raw <select> element whose ID is state. Although the <form> is submitted to ProcessForm action this method is not described below as it's not directly related to the functioning of the DropDownLists.

Now, add a <script> reference to jQuery library and also add a <script> block in the head section of the view. Then write the following jQuery code in the <script> block:

$(document).ready(function () {
  $("#state").prop("disabled", true);
  $("#country").change(function () {
    if ($("#country").val() != "Please select") {
       var options = {};
       options.url = "/home/getstates";
       options.type = "POST";
       options.data = JSON.stringify({ country: $("#country").val() });
       options.dataType = "json";
       options.contentType = "application/json";
       options.success = function (states) {
       $("#state").empty();
       for (var i = 0; i < states.length; i++) {
         $("#state").append("<option>" + states[i] + "</option>");
       }
       $("#state").prop("disabled", false);
    };
    options.error = function () { alert("Error retrieving states!"); };
    $.ajax(options);
  }
  else {
    $("#state").empty();
    $("#state").prop("disabled", true);
  }
 });
});

The above code shows the ready() handler. Inside the ready() handler, you first disable the state DropDownList using prop() method. The prop() method sets the disabled DOM property to true and thus disables the state DropDownList. Then the change() method is used to wire change event handler of the country DropDownList. The change event handler will be called whenever selection in the country DropDownList changes. The change handler function first checks value selected in the country DropDownList. If it is other than "Please select", the code creates an options object. The options object holds various settings for the Ajax request to made to the server for retrieving the state values. The url property points to the GetStates() action method. The type property is set to POST indicating that a POST method will be used while making Ajax request. The data property contains JSON representation of the country selected in the country DropDownList. Note that the name of this property has to match with the name of the GetStates() method parameter. The dataType and contentType are set to json and application/json respectively. These properties indicate the data type of the response and request respectively.

The success handler function is called when the Ajax call to GetStates() is successful. The success handler function receives the states returned from the GetStates() method as an array of JSON objects. Inside the success handler you iterate through the states array and add <option> elements to the state DropDownList using append() method. Before appending the newly fetched states the state DropDownList is emptied. Once t he states are populated the disabled property of the states DropDownList is set to true using prop() method.

The error handler function simply displays an error message in an alert dialog.

Finally, an Ajax call is made using $.ajax() method of jQuery and the options object is passed as its parameter.

That's it! Run the application and test whether states are populated as expected.

READ MORE
...