Cascading DropDownList is a technique where we populate a child DropDownList based on the parent DropDownList selection. For example, when we select a state in States DropDownList, it will populate the City DropDownList based on the state selected for a personal information input form. In .Net world, we can achieve this by populating the child DropDownList from the SelectedIndex changed event of parent.
Well, there are multiple ways to implement this in AJAX world. One way is to keep both the DropDownList in an UpdatePanel and populate the child in SelectedIndex changed event of parent. Another way is to use the CascadingDropDown extender in AJAXControlToolkit. Since these 2 techniques uses ASP.Net AJAX framework, the communication is still bulky.
In this article, we will implement the same using the ajax method in jQuery by using JSON. Before moving into the actual article, it is required to know some of the basics.
jQuery
jQuery is a light weight JavaScript library that simplifies the client side DOM manipulation, event handling, ajax communication easier and faster. Read my previous article which will give you a introduction about jQuery and integrating it with our project – Using JQuery in ASP.Net AJAX Applications – Part 1
JSON
JSON means JavaScript Object Notation. It is a simple text based, human readable data format that is widely used in AJAX application to transfer data as an alternative to XML format. In simple words, it is simply key- value pairs, separated by commas and enclosed in curly braces.
Moving forward, in this article we will build cascading DropDownList by using the above technologies. We will take the same example we discussed earlier in this article i.e. a state DropDownList and a Cities DropDownList which gets filled when a state is selected.
In particular, we will implement an HttpHandler that can return the collection of cities available in a state in JSON format by accepting state as a query string parameter. This HttpHandler will be called using jQuery getJSON() method when a state is selected in the parent DropDownList and it will populate the child DropDownList using JSON data.
Building Cascading DropDownList
- You can create a new Asp.Net website project in your Visual Studio 2008 using the language of your choice. I have used C# as the language of my choice.
- Drag DropDownList control from the toolbox and change its ID to ddlStates.
- For easy understanding and simplicity, I will hardcode the ListItems. You can bind it from database in your case. This DropDownList will be the parent.
- Drag another DropDownList control and rename its ID to ddlCities. This will be child DropDownList control.
<table>
<tr>
<td>State</td>
<td>
<asp:DropDownList ID="ddlStates" runat="server">
<asp:ListItem Value="0">Select</asp:ListItem>
<asp:ListItem Value="1">Tamil Nadu</asp:ListItem>
<asp:ListItem Value="2">Karnataka</asp:ListItem>
</asp:DropDownList>
</td>
</tr>
<tr>
<td>Cities</td>
<td>
<asp:DropDownList ID="ddlCities" runat="server">
</asp:DropDownList>
</td>
</tr>
</table>
Next, we will construct an HttpHandler which can accept the stateID and give back the list of cities available in that state in JSON format.
To do this, Right click the project in solution and click “Add New Item”. Select “Generic Hanlder”. I have named it as LoadCities.ashx. The HttpHanlder will accept StateID as a query string parameter to fetch the cities from database. Here, I have hard-coded the cities based on the state id for easy understanding. Next, the cities should be returned back in JSON format from the HttpHandler. To know more about JSON and JSON format, please visit the JSON site referenced in JSON section (Move Top) of this article.
To understand better, i will give a sample JSON data format that should be returned for a stateid.
[{"City":"Chennai","ID":"1"},{"City":"Coimbatore","ID":"2"}]
As I said earlier, JSON format is simply key- value pairs, separated by commas and enclosed in curly braces. Thus, each city is enclosed in curly braces. So, in HttpHanlder we need to construct the data in JSON format and return it back to the caller.
Refer the below code,
<%@ WebHandler Language="C#" Class="LoadCities" %>
using System;
using System.Web;
using System.Text;
public class LoadCities : IHttpHandler {
public void ProcessRequest (HttpContext context) {
string StateID = context.Request.QueryString["StateID"];
//Contact Database to get th elist of cities based on StateID
StringBuilder strCities = new StringBuilder();
if (StateID == "1")
{
strCities.Append("[");
strCities.Append("{");
strCities.Append("\"City\":\"Chennai\",");
strCities.Append("\"ID\":\"1\"");
strCities.Append("},");
strCities.Append("{");
strCities.Append("\"City\":\"Coimbatore\",");
strCities.Append("\"ID\":\"2\"");
strCities.Append("}");
strCities.Append("]");
}
else if (StateID == "2")
{
strCities.Append("[");
strCities.Append("{");
strCities.Append("\"City\":\"Bangalore\",");
strCities.Append("\"ID\":\"1\"");
strCities.Append("},");
strCities.Append("{");
strCities.Append("\"City\":\"Belgaum\",");
strCities.Append("\"ID\":\"2\"");
strCities.Append("}");
strCities.Append("]");
}
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.Write(strCities.ToString());
context.Response.End();
}
public bool IsReusable {
get {
return false;
}
}
}
I have hard coded only for 2 states, you can loop through the result set from database and give back the data in JSON format.
Calling HttpHanlder from jQuery
There are some handful of Ajax methods available in jQuery for AJAX communications. Here, I am going to use getJSON method to get the result back from HttpHanlder and bind the DropDownList control.
Read my previous article Using JQuery in ASP.Net AJAX Applications – Part 1.
This will show you how to integrate jQuery and use Visual Studio intellisense with our project.
We will declare an onchange event for the parent DropDownList which will make the AJAX call to the server to fetch the JSON data. Refer the below code,
<script src="_scripts/jquery-1.2.6.js" type="text/javascript"></script>
<script language="javascript">
$(document).ready(function() {
$("#ddlStates").change(function() {
$("#ddlCities").html("");
var StateID = $("#ddlStates > option[@selected]").attr("value");
if (StateID != 0) {
$.getJSON('LoadCities.ashx?StateID=' + StateID, function(cities) {
$.each(cities, function() {
$("#ddlCities").append($("<option></option>").val(this['ID']).html(this['City']));
});
});
}
});
});
</script>
Update
If you are using jQuery library 1.3.2, @ character in selector expression have to be removed since the use of @ with the attribute is deprecated. So, change the stateid selection like,
var StateID = $("#ddlStates > option[selected]").attr("value");
The getJSON method will be called for every state selection except for the value of “select” in parent DropDownList. When the JSON result is returned it will call the call-back function(2nd argument of getJSON method) which will populate the child DropDownList control.
Execute the page and you can see Cascading DropDownList in action.
So far so good, now when we try to save the data again or if there is any postback to the server after the above step, we will get an exception with a message,
Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.
What is the reason for the above exception?
ASP.Net performs a validation on every postback called EventValidation which records the values, controls at every render and it will check the data and control that is generating the event or postback is in the list recorded in the last render. For example, if a dropdown with values 1, 2, 3 is rendered to the client, for the next postback event if someone tries to add a fourth option say “4” in the client (using JavaScript) and post it to the server the validation fails and the runtime will throw an exception. ASP.Net will predict it as an attack by default since the content are different and will throw an exception. Since, the child DropDownList is loaded in client side without a normal postback it is considered as an attack and the validation will fail. The result is the above exception.
Resolutions
There are several ways to prevent the above exception. You can see some of the resolution which can be done to prevent the above exception below.
- To resolve the above issue, we can disable the enableEventValidation either in web.config or in page level.
in Web.Config or,
<%@ Page EnableEventValidation=”false” %> in a page attribute.
- The risk in above approach is, we are by-passing the security validation which may result in intruder attacking our system. Alternate way to resolve the above issue will be using RegisterForEventValidation() Methods in ClientScriptManager class. Read my article, Using JavaScript Effectively in ASP.Net 2.0 – PART 2 to know more about it. Refer the RegisterForEventValidation() Methods section in the article.
- An Alternate and easiest way will be replacing the child DropDownList as a HTML select control by setting runat attribute to server. This is the very easiest way to prevent the above exception. So, the child DropDownList can be re-written as,
<select ID="ddlCities" runat="server">
</select>
Download the source code packed with this article in Download section to see Cascading DropDownList in action.
To Access the selected value from server side
Response.Write(Request["ddlCities"]);
Conclusion
Thus, we have understood an alternate way to build a cascading DropDownList control which is light weight when compared to ASP.Net AJAX communication. Download the code and see it in action.
Happy Coding!!