Click here to Skip to main content
Click here to Skip to main content

AJAX for Beginners (Part 2) - Using XMLHttpRequest and jQuery AJAX to implement a cascading dropdown

By , 14 Jan 2013
 

There are three articles in this mini series:

Introduction

This article discusses the ways ASP.NET applications can implement asynchronous functionality, i.e., AJAX by using XMLHttpRequest object and jQuery AJAX.

Background

In Part 1 of this series we have seen various ways an ASP.NET developer can implement the AJAX functionality in the web applications. We have also seen how to use the ASP.NET AJAX server controls. Now the focus of this article will be on using XMLHttpReuqest object and jQuery AJAX to implement the asynchronous behavior in the web applications.

XMLHttpObject facilitates the exchange of data between client and server behind the scenes i.e. the partial page update is possible using the XMLHttpObject.

jQuery is a JavaScript framework which makes a lot of client side work easy for the developers. jQuery AJAX is a set of routines that provides behind the scenes communication between client and server thus facilitating partial page updates.

Using the code

In this article we will try to work on a very common problem faced by many developers. We will try to implement the cascading dropdown lists using AJAX. We will implement this first using the XMLHttpObject and then by jQuery AJAX.

Before starting with the problem at hand let us understand the solution and the desired functionality. Let us say we have a database keeping a list of all the continents and countries. The user will be presented with two drop down lists. First dropdown will contain a list of continents and when user select any continent from this list the second dropdown list should be updated asynchronously i.e. without causing any postback.

ajax article 2 images

Let us look at the Database table containing the list of continents and countries and the containing data.

ajax article 2 images

Note: The database has not been optimized or normalized in any way because that was not the focus of this article.

Now we have a helper class that takes care of all the database communications. This class ideally should be present as a separate solution for Data Access layer but for the sake of simplicity I have created this class.

public class DBHelper
{   
    public static DataTable GetContinentList()
    {
        DataTable result = null;

        try
        {
            using (SqlConnection con = new SqlConnection(
              ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
            {
                using (SqlCommand cmd = con.CreateCommand())
                {
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = "select distinct continentName from Countries";

                    using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                    {
                        result = new DataTable();
                        da.Fill(result);
                    }
                }
            }
        }
        catch (Exception)
        {
            //Pokemon exception handling
        }
        return result;
    }

    public static DataTable GetCountriesList(string continentNmame)
    {
        DataTable result = null;
        
        try
        {
            using (SqlConnection con = new SqlConnection(
              ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
            {
                using (SqlCommand cmd = con.CreateCommand())
                {
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = "select countryName from Countries where continentName = @continent";
                    cmd.Parameters.Add(new SqlParameter("@continent", continentNmame));

                    using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                    {
                        result = new DataTable();
                        da.Fill(result);
                    }
                }
            }
        }
        catch (Exception)
        {
            //Pokemon exception handling
        }
        return result;
    }
}

This class is will help in retrieving the list of continents and list of countries specific to that continent. Let us now start working on the real problem.

Using XMLHttpObject

Let us create a page with two drop down lists (default.aspx). We will initialize the first drop down list with first continent name and second dropdown list with the countries of that continent. We will then use XMLHttpObject to change the contents of second dropdown list based on user selection of first dropdown. The code behind of this page will contain the logic for page_load only.

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack == false)
    {
        //Let us populate the list of continents in the first drop down
        drpContinent.DataSource = DBHelper.GetContinentList();
        drpContinent.DataTextField = "continentName";
        drpContinent.DataValueField = "continentName";
        drpContinent.DataBind();

        //Set the second dropdown as the list of all countries of selected continent
        drpCountry.DataSource = DBHelper.GetCountriesList(drpContinent.SelectedValue);
        drpCountry.DataTextField = "countryName";
        drpCountry.DataValueField = "countryName";
        drpCountry.DataBind();
    }
}

Now next thing we want to do is to handle the onchange event of the first dropdown on client side.

<asp:DropDownList ID="drpContinent" runat="server" onchange="UpdateCountries();">
</asp:DropDownList>

Now to use XMLHttpObject to get the list of countries based on user selection, we need to do the following:

  1. Create the XmlHttpObject.
  2. Retrieve the current user selection of first dropdown
  3. Pass this value to a web page on server as query string using XMLHttpObject.
  4. Handle the response of this async request we just made.
  5. Retrieve the values in the response.
  6. Change the second dropdown lists items as per the new values found in response.

The important thing to note in the above algorithm is that we need a page that can handle this asynchronous request, extract the query string and then push the results to the response. Let us create a page called frmForAjaxCalls.aspx for this purpose and implement the functionality.

public partial class frmForAjaxCalls : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string continentName = Request.QueryString["cont"] as string;

        if (continentName != null)
        {
            DataTable table = DBHelper.GetCountriesList(continentName.Trim());

            string result = string.Empty;
            
            foreach (DataRow r in table.Rows)
            {
                result += r["countryName"].ToString() + ";";
            }

            Response.Clear();
            Response.Write(result);
            Response.End();
        }
    }
}

Now the only thing remaining is the client side JavaScript code that will call this page using XMLHttpObject. Following code will show how it is done.

var xmlHttp;
    
function UpdateCountries()
{
    //Let us create the XML http object
    xmlHttp = null;
    
    if(window.XMLHttpRequest)
    {
        //for new browsers
        xmlHttp = new XMLHttpRequest();
    }
    else if(window.ActiveXObject)
    {
        //for old ones
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); 
    }
    
    if(xmlHttp != null)
    {
        //eveyhthing so far is just fine, lets proceed
        
        //Retreive the value of the first drop down list
        var contName = document.getElementById('<%=drpContinent.ClientID %>').value; 
        
        //Handle the response of this async request we just made(subscribe to callback)
        xmlHttp.onreadystatechange=state_Change;
        
        //Pass the value to a web page on server as query string using XMLHttpObject.
        xmlHttp.open("GET","frmForAjaxCalls.aspx?cont="+contName,true);
        xmlHttp.send(null); 
    }
}

//Handle the response of this async request
function state_Change() 
{
    if (xmlHttp.readyState==4) 
    {
        // 4 = “loaded” 
        if (xmlHttp.status==200) 
        {
            //request was successful. so Retrieve the values in the response.
            var countries = xmlHttp.responseText.split(';');
            var length = countries.length;
            
            //Change the second dropdownlists items as per the new values foudn in response.
            //let us remove existing items
            document.getElementById('<%=drpCountry.ClientID %>').options.length = 0;
            
            //Now add the new items to the dropdown.
            var dropDown = document.getElementById('<%=drpCountry.ClientID %>');                                
            for(var i = 0; i < length - 1; ++i)
            {
                var option = document.createElement("option");
                option.text = countries[i];
                option.value = countries[i];
                
                dropDown.options.add(option);
            }
        }
    }
}

Now when we run this page we can see that the selection on first dropdown list will trigger the async communication with the server and the second dropdown list will be populated with the values of countries in that continent. All this was done without having any postback to the server.

Using jQuery AJAX

Let us create a similar page with two drop down lists (default2.aspx). We will initialize the first drop down list with first continent name and second dropdown list with the countries of that continent. We will then use jQuery AJAX to change the contents of second dropdown list based on user selection of first dropdown. The code behind of this page will contain the logic for page_load.

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack == false)
    {
        //Let us populate the list of continents in the first drop down
        drpContinent.DataSource = DBHelper.GetContinentList();
        drpContinent.DataTextField = "continentName";
        drpContinent.DataValueField = "continentName";
        drpContinent.DataBind();

        //Set the second dropdown as the list of all countries of selected continent
        drpCountry.DataSource = DBHelper.GetCountriesList(drpContinent.SelectedValue);
        drpCountry.DataTextField = "countryName";
        drpCountry.DataValueField = "countryName";
        drpCountry.DataBind();
    }
}

Now unlike XMLHttpObject, if we are using jQuery we don't have to create another page to handle the async request. What we can do is to have a static function in the asme page (or we could create a separate page if we want to) that will take some arguments and return some value. Passing the argument to this function, invoking this function and and handling the result will be the jQuery's responsibility on client side. Let us look at this function:

[System.Web.Services.WebMethod]
public static string OnContinentChange(string continentName)
{
    DataTable table = DBHelper.GetCountriesList(continentName.Trim());

    string result = string.Empty;

    foreach (DataRow r in table.Rows)
    {
        result += r["countryName"].ToString() + ";";
    }

    return result;
}

This static function should also be decorated with an attribute WebMethod. This indicates that this method will be called from client side.

Note: This static method with WebMethod attribute can be thought of as the small web service that can be accessed from client side using this page's URL.

Now to use jQuery AJAX to get the list of countries based on user selection we need to do the following:

  1. Handle the onchange event of the first dropdown.
  2. Retrieve the current user selection of first dropdown
  3. Create a JSON object for passing this data to the server.
  4. Specify the page/method name to be called.
  5. Handle the response callback.
  6. Retrieve the values in the response.
  7. Change the second dropdownlists items as per the new values found in response.

Following code will shows how it is done using jQuery:

$(document).ready(function() {  
    //Handle the change event for the drop down list
    $("#drpContinent").change(function() { 
        //create the ajax request
        $.ajax( {
            type: "POST", //HTTP method
            url: "Default2.aspx/OnContinentChange", //page/method name
            data: "{'continentName':'"+$('#drpContinent').val() +"'}", //json to represent argument
            contentType: "application/json; charset=utf-8", 
            dataType: "json",
            success: function(msg) { //handle the callback to handle response                
            //request was successful. so Retrieve the values in the response.
            var countries = msg.split(';');
            var length = countries.length;
            
            //Change the second dropdownlists items as per the new values foudn in response.
            //let us remove existing items
            document.getElementById('<%=drpCountry.ClientID %>').options.length = 0;
            
            //Now add the new items to the dropdown.
            var dropDown = document.getElementById('<%=drpCountry.ClientID %>');
            for(var i = 0; i < length - 1; ++i) {
                var option = document.createElement("option");
                option.text = countries[i];
                option.value = countries[i];
                
                dropDown.options.add(option);
            }
          }
       });
   });
});

Now when we run this page we can see that the selection on first dropdown list will trigger the async communication with the server and the second dropdown list will be populated with the values of countries in that continent. All this was done without having any postback to the server.

Points of Interest

We have seen two ways we can implement AJAX behavior in an ASP.NET website. First method was using XMLHttpObject and second one is using the jQuery AJAX. We have had only a cursory look at these two ways to understand how things can be done. There are lot of options related to both these approaches that can be customized to have better control over the asynchronous communication. I suggest we reading about these two approaches in details will really help in better understanding to things.

We also solved a very common problem that developers (new) face and that is creating cascading dropdown lists. This article presents 2 ways of doing that. We can also use AJAX controls toolkit to achieve this and many more AJAX functionalities. But perhaps that deserves a separate discussion.

History

  • 12 Jun 2012: First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Rahul Rajat Singh
Software Developer (Senior)
India India
Member
I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems.
 
Some CodeProject Achievements:
  • 9th in Best Web Dev article of March 2013
  • 7th in Best Web Dev article of January 2013
  • 2nd in Best C# article of December 2012
  • 5th in Best overall article of December 2012
  • 5th in Best C# article of October 2012
  • 4th in Best Web Dev article of September 2012
  • 3rd in Best C# article of August 2012
  • 5th in Best Web Dev article of August 2012
  • 5th in Best Web Dev article of July 2012
  • 3rd in Best Overall article of June 2012
  • 2nd in Best Web Dev article of June 2012
  • 5th in Best Web Dev article of May 2012
  • 6th in Best Web Dev article of April 2012
  • 4th in Best C++ article of April 2012
  • 5th in Best C++ article of March 2012
  • 7th in Best Web Dev article of March 2012
  • 5th in Best Web Dev article of February 2012
  • 7th in Best Web Dev article of February 2012
  • 9th in Best Web Dev article of February 2012
  • 5th in Best C++ article of February 2012

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5mvpMichael Haephrati21 Feb '13 - 8:17 
Great work
QuestionExcellent post, but jquery ajax didn't work :(memberMember 440295618 Jan '13 - 20:03 
Thanks for the post! Really helped me in understanding how to integrate javascript ajax to asp.net. However, the jquery ajax script did not work for me Frown | :( when I change the value of the drop down, nothing happened. Any ideas why?
AnswerRe: Excellent post, but jquery ajax didn't work :(membercaozhy__30 Jan '13 - 15:53 
Frown | :( me too. i want to konw why it's?
AnswerRe: Excellent post, but jquery ajax didn't work :(membercaozhy__30 Jan '13 - 16:11 
var countries = msg.d.split(';'); Laugh | :laugh:
GeneralRe: Excellent post, but jquery ajax didn't work :(memberMember 440295631 Jan '13 - 0:18 
Thanks caozhy_, I find it a bit weird how the variable name is d!
Questionvar countries = msg.split(';'); gives error [modified]memberMukund Thakker16 Jan '13 - 0:52 
var countries = msg.split(';'); gives error
TypeError: msg.split is not a function
msg return object and not string.

modified 16 Jan '13 - 7:01.

GeneralCode to run from MS Access DatabasememberSergheiT15 Jan '13 - 9:02 
For anyone who wants to use MS Access Database (2007 and later) add connection string to Web.Config file and Database file to App_data folder
 
  <connectionStrings>
    <add name="LocalDatabase" connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\SampleDatabase.accdb"/>
  </connectionStrings>
 

and use DbHelper class
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
 
/// <summary>
/// Summary description for DbHelper
/// </summary>
public class DbHelper
{
	public DbHelper()
	{
		//
		// TODO: Add constructor logic here
		//
	}
 
        public static DataTable GetContinentList()
        {
            DataTable result = null;
 
            try
            {
                using (OleDbConnection con = new OleDbConnection(
                  ConfigurationManager.ConnectionStrings["LocalDatabase"].ConnectionString))
                {
                    using (OleDbCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandType = CommandType.Text;
                        cmd.CommandText = "select distinct continentName from Countries";
 
                        using (OleDbDataAdapter da = new OleDbDataAdapter(cmd))
                        {
                            result = new DataTable();
                            da.Fill(result);
                        }
                    }
                }
            }
            catch (Exception)
            {
                //Pokemon exception handling
            }
            return result;
        }
 
        public static DataTable GetCountriesList(string continentNmame)
        {
            DataTable result = null;
 
            try
            {
                using (OleDbConnection con = new OleDbConnection(
                  ConfigurationManager.ConnectionStrings["LocalDatabase"].ConnectionString))
                {
                    using (OleDbCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandType = CommandType.Text;
                        cmd.CommandText = "select countryName from Countries where continentName = @continent";
                        cmd.Parameters.Add(new OleDbParameter("@continent", continentNmame));
 
                        using (OleDbDataAdapter da = new OleDbDataAdapter(cmd))
                        {
                            result = new DataTable();
                            da.Fill(result);
                        }
                    }
                }
            }
            catch (Exception)
            {
                //Pokemon exception handling
            }
            return result;
        }
    
}
SergoT

GeneralMy vote of 4memberSergheiT15 Jan '13 - 6:47 
Good Article. Easy to follow
But I am getting this error
Uncaught TypeError: Object #<object> has no method 'split' Default5.aspx:29
 
$.ajax.success Default5.aspx:29
success jquery-1.4.1.js:5138
xhr.onreadystatechange</object>
GeneralMy vote of 5memberresi243114 Jan '13 - 22:33 
very good one
GeneralMy vote of 5memberMember 191236710 Jan '13 - 15:40 
Excellent article.
GeneralJavascript valuememberSubha Ranjan Saha21 Dec '12 - 20:46 
I have a textbox. On change of this textbox the function filladults() is called. It is going into this function but what I want is to display the value of noofpsersons in the adult field in the form. The html code is also given for both txtnopersons and txtadult
 

function filladult(nopersons)
{
 
alert("you are here :" + nopersons);
 
document.getElementById('txtadult').value= nopersons;
}
 
---------
<asp:TextBox ID="txtnoofperson" runat="server" BorderColor="LightGray" BorderStyle="Solid"
BorderWidth="1px" CssClass="tabForm" Width="50px" OnFocus="this.style.backgroundColor='#F9FEE0',this.style.borderColor='#000000'"
OnBlur="this.style.backgroundColor='',this.style.borderColor=''"
OnTextChanged="txtnoperson" onchange ="filladult(this.value)">
<cc1:FilteredTextBoxExtender ID="txtnoofperson_FilteredTextBoxExtender" runat="server"
Enabled="True" FilterType="Numbers" TargetControlID="txtnoofperson">

--------
<asp:TextBox ID="txtadult" runat="server"  BorderColor="LightGray"
                                                                                                            BorderStyle="Solid" BorderWidth="1px" CssClass="tabForm" Width="50px" OnFocus="this.style.backgroundColor='#F9FEE0',this.style.borderColor='#000000'"
                                                                                                            OnBlur="this.style.backgroundColor='',this.style.borderColor=''"
                                                                                                            Enabled="False"></asp:TextBox>

QuestionquestionmemberMember 955320210 Dec '12 - 23:38 
what is Pokemon exception handling
AnswerRe: questionmemberRahul Rajat Singh11 Dec '12 - 0:23 
For when you just Gotta Catch 'Em All.
try
{
    // do something
}
catch
{
    // catch em all
} 
 
refer this[^]
Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore, Dream. Discover.

AnswerArticle of the Day on Microsoft's sitememberRahul Rajat Singh10 Dec '12 - 18:40 
This article has been selected as Article of the Day on Microsoft's site http://www.asp.net/community[^] on 07 December 2012.
 
Rahul Rajat Singh
07 December 2012.

Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore, Dream. Discover.

Questionerror object xmlhttprequestmembermasterlio24 Oct '12 - 7:41 
Hi, I have the piece of code below, why is it that on firefox I get the error:xmlhttprequest
Thanks,
 

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 
<title>Ajax Example in Struts 1e</title>
 
 <script type="text/javascript" src="<%= applicationRootContext %>/js/jQuery.js"></script>
 
 <script type="text/javascript">
 
    function doAjaxPost() {
 
        // get the form values

        var name = $('#name').val();
 

        $.ajax({
 
           type: "POST",
 
           url: "newUser.do",
 
            data:"name=" +name,
 
            success: function(response){
 
                // we have the response

                $('#info').html(response);
 
            },
 
            error: function(e){
 
                alert('Error: ' + e);
 
            }
 
        });
 
    }
 
</script>

QuestionEasy to understand beginnersmembersuhelsa5 Sep '12 - 21:16 
Excellent
AnswerRe: Easy to understand beginnersmemberRahul Rajat Singh5 Sep '12 - 22:50 
Thanks for the feedback.
Every now and then say, "What the Elephant." "What the Elephant" gives you freedom. Freedom brings opportunity. Opportunity makes your future.

GeneralMy vote of 5membersuhelsa5 Sep '12 - 21:15 
Excellent,Easy to understand begginers
GeneralBrilliantmemberA.J Bosch21 Aug '12 - 9:58 
thanks alot man this really saved me hours of research time Big Grin | :-D
I'm not anti social, I'm Just not user friendly...

GeneralMy vote of 5memberMember 936514221 Aug '12 - 9:34 
Muchas gracias por este post, me ayud� mucho para realizar un trabajo para la universidad.
QuestionAJAX for beginners (Part 2) - Using XMLHttpRequest and jQuery AJAX to implement a cascading dropdownmemberyhay20 Aug '12 - 4:57 
Good, but my question is why use the XMLHttpRequest or jQuery AJAX method to implement a cascading dropdown? What's the advantage over just using AJAX?
GeneralMy vote of 4memberMember 917670518 Aug '12 - 12:29 
good example for the use of Jquery
GeneralMy vote of 5membermanoj kumar choubey10 Jul '12 - 22:29 
Nice
GeneralMy vote of 5memberglglak13 Jun '12 - 23:12 
very easy to understand, and he added a lot of code, algorithms and used different methods to achieve the same goals,
Generalgoodmemberqian4040112 Jun '12 - 22:15 
It is easy to understand.
GeneralMy vote of 4memberFabrizio198612 Jun '12 - 11:26 
Nice tutorials, to make it perfect you could add a section on how to compile the javascript and other resources into a dll for reuse as webresources.
Thank you
GeneralRe: My vote of 4memberSebastián Poliak13 Jun '12 - 6:20 
Yes! That's would be great
GeneralMy vote of 5memberCarsten V2.012 Jun '12 - 11:06 
Hello Rahul,
 
thank you for this further tutorial! Please do keep it up... Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 14 Jan 2013
Article Copyright 2012 by Rahul Rajat Singh
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid