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

Cascading Menus Without Page Refresh With the AJAX Control Toolkit

By , 12 Jul 2011
 

Sample Image

Introduction

This is a very easy and user friendly technique for web applications to implement cascading menus without page refresh.

You do not have to know about AJAX functions, just download the AJAX Control Toolkit on CodePlex and follow the steps described in this article. When you have two dropdownlists and both of them are related to each other, such as Country and City in a registration page where you want to save information about the user's hometown. When you choose a certain row from the first dropdownlist (Country), you will expect the second dropdownlist (City) to be filtered according to the chosen row without refreshing the page. This article shows a very easy and user friendly solution that can be used in web applications.

Background: What is the AJAX Control Toolkit?

The ASP.NET AJAX Control Toolkit is an Open-Source project built on top of the Microsoft ASP.NET AJAX framework, and contains more than 30 controls that enable you to easily create rich, interactive web pages. If you want to know more about it, visit here.

Using the code

The first step is to download the AJAX Control Toolkit from here for .NET 3.5 or here for .NET 4.0.

Copy the AJAX Control Toolkit to the Bin folder and right click on Solution, choose Add Reference, in the Browse tab, double click on the Bin folder, and double click on AJAX Control Toolkit, then on the Build menu, click Rebuild.

Database

Create a database and name it "Db". Here is the query to create the required tables:

--Create Country Table 
CREATE TABLE [dbo].[tblCountry](
    [Country] [nvarchar](50) NULL,
    [IDC] [int] IDENTITY(1,1) NOT NULL
    ) ON [PRIMARY]

--Fill Country Table 
insert into dbo.tblCountry(Country) values('United States')
insert into dbo.tblCountry(Country) values('United Kingdom')
insert into dbo.tblCountry(Country) values('Spain')
insert into dbo.tblCountry(Country) values('France')
insert into dbo.tblCountry(Country) values('Norway')

--Create City Table 
CREATE TABLE [dbo].[tblCity](
[City] [nvarchar](50) NULL,
[CountryID] [int] Not NULL,
[ID] [int] IDENTITY(1,1) NOT NULL
)
ON [PRIMARY]

--Fill City Table 
insert into dbo.tblCity(City,CountryID) values('Michigan',1)
insert into dbo.tblCity(City,CountryID) values('New York',1)
insert into dbo.tblCity(City,CountryID) values('London',2)
insert into dbo.tblCity(City,CountryID) values('Barcelona',3)
insert into dbo.tblCity(City,CountryID) values('Madrid',3)
insert into dbo.tblCity(City,CountryID) values('Paris',4)
insert into dbo.tblCity(City,CountryID) values('Kristiansand',5) 
insert into dbo.tblCity(City,CountryID) values('Oslo',5)

Visual Studio 2008 - .NET 3.5

Create a website and name it Cascading menus. Create a Web Form and name it CascadingDropDown.aspx. In the HTML view, write the code below. The code is a little different between C# and VB in this section. If you are a VB coder, modify two sections in the page tag in the first line:

  • language="VB"
  • CodeFile="CascadingDropDown.aspx.vb"
<%@ Page Language="C#" AutoEventWireup="false" 
         CodeFile="CascadingDropDown.aspx.cs" Inherits="CascadingDropDown" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" 
         TagPrefix="ajaxToolkit" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>CascadingDropDown</title>
</head>
<body>
<form id="form1" runat="server">
<ajaxToolkit:ToolkitScriptManager  ID="ScriptManager1" runat="server" > 
</ajaxToolkit:ToolkitScriptManager>
<div>
<asp:DropDownList ID="ddListCountry" runat="server" Width="170" /> 

<asp:DropDownList ID="ddListCity" runat="server" Width="170" /> 

<ajaxToolkit:CascadingDropDown 
  ID="CascadingCountry" 
  runat="server"
  TargetControlID="ddListCountry"
  Category="Country"
  PromptText="Please select a Country"
  LoadingText="[Loading Country...]"
  ServicePath="Cascading.asmx"
  ServiceMethod="GetCountries" >
  </ajaxToolkit:CascadingDropDown>

<ajaxToolkit:CascadingDropDown 
  ID="CascadingCity" 
  runat="server"
  TargetControlID="ddListCity"
  Category="City"
  PromptText="Please select a City"
  LoadingText="[Loading City...]"
  ServicePath="Cascading.asmx"
  ServiceMethod="GetCities"
    ParentControlID="ddListCountry" >
  </ajaxToolkit:CascadingDropDown>
</div>

</form>
</body>
</html>

For VB: Create Web Service: Solution > right click > Add New Item > Web Service >. Name: Cascading.asmx. Language: Visual Basic. Go To > App_Code > Cascading.vb.

' (c) Copyright Microsoft Corporation.
' This source is subject to the Microsoft Public License.
' See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
' All other rights reserved.
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Collections.Generic
Imports AjaxControlToolkit
Imports System.Data
Imports System.Data.SqlClient
Imports System.Text.RegularExpressions
Imports System.Collections.Specialized
Imports System.Xml

' To allow this Web Service to be called from script,
' using ASP.NET AJAX, uncomment the following line.
<System.Web.Script.Services.ScriptService()> _
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class Cascading
    Inherits System.Web.Services.WebService
    Dim cn As New SqlClient.SqlConnection()
    Dim ds As New DataSet
    Dim dt As New DataTable

<WebMethod()> _
Public Function GetCountries(ByVal knownCategoryValues As String, _
       ByVal category As String) As CascadingDropDownNameValue()

    'ADO.Net
    Dim strCn As String = "data source=.;Initial Catalog=Db;Integrated Security=True"

    cn.ConnectionString = strCn
    Dim cmd As New SqlClient.SqlCommand
    cmd.Connection = cn
    cmd.CommandType = CommandType.Text
    cmd.CommandText = "select * from tblCountry"

    Try
        cn.Open()
        cmd.ExecuteNonQuery()
        Dim da As New SqlDataAdapter(cmd)
        da.Fill(ds)
    Catch ex As Exception
    Finally
        cn.Close()
    End Try

    dt = ds.Tables(0)
    Dim CountryValues As New List(Of CascadingDropDownNameValue)()

    For Each row As DataRow In dt.Rows
       CountryValues.Add(New CascadingDropDownNameValue(row("Country").ToString(), _
                         row("IDC").ToString()))
    Next

    Return CountryValues.ToArray()

End Function

<WebMethod()> _
Public Function GetCities(ByVal knownCategoryValues As String, _
                ByVal category As String) As CascadingDropDownNameValue()

    Dim kv As StringDictionary = _
        CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues)
    'ContainsKey("Country") is one of property in Ajaxcontroltoolkit
    Dim countryId As Integer

    If ((Not kv.ContainsKey("Country")) Or _
        (Not Int32.TryParse(kv("Country"), countryId))) Then
        Return Nothing
    End If

    'ADO.Net
    Dim strCn As String = "data source=.;Initial Catalog=Db;Integrated Security=True"
    cn.ConnectionString = strCn
    Dim cmd As New SqlClient.SqlCommand
    cmd.Connection = cn
    '-----I Defined a parameter instead of passing value 
    '               directly to prevent sql injection--------'
    cmd.CommandText = "select * from tblCity where CountryID=@myParameter Order by City"
    cmd.Parameters.AddWithValue("@myParameter", countryId.ToString())

    Try
        cn.Open()
        cmd.ExecuteNonQuery()
        Dim da As New SqlDataAdapter(cmd)
        da.Fill(ds)
    Catch ex As Exception
    Finally
        cn.Close()
    End Try

    dt = ds.Tables(0)
    Dim CityValues As New List(Of CascadingDropDownNameValue)()

    For Each row As DataRow In dt.Rows
       CityValues.Add(New CascadingDropDownNameValue(row("City").ToString(), _
                      row("ID").ToString()))
    Next

    Return CityValues.ToArray()

End Function

End Class

For C#: Web Service: Solution > right click > Add New Item > Web Service >. Name: Cascading.asmx. Language: C#. Go To > App_Code > Cascading.cs.

// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License.
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
// All other rights reserved.
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Collections.Generic;
using AjaxControlToolkit;
using System.Data;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using System.Xml;

///<summary>
/// Summary description for Cascading
///</summary>

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script,
// using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class Cascading : System.Web.Services.WebService {

    public Cascading () {
        //Uncomment the following line if using designed components
        //InitializeComponent();
    }

    [WebMethod]
    public CascadingDropDownNameValue[] GetCountries(string knownCategoryValues, 
                                        string category)
    {
        //ADO.Net
        SqlConnection cn =new SqlConnection();
        DataSet ds = new DataSet();
        DataTable    dt = new DataTable();
        string strCn = "data source=.;Initial Catalog=Db;Integrated Security=True";
        cn.ConnectionString = strCn;
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = cn;
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = "select * from tblCountry";

        try
        {
            cn.Open();
            cmd.ExecuteNonQuery();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            da.Fill(ds);
        }
        catch
        {
        }
        finally
        {
            cn.Close();
        }
        dt = ds.Tables[0];

        List<CascadingDropDownNameValue> CountryValues = 
                    new List<CascadingDropDownNameValue>();
        foreach (DataRow row   in dt.Rows)
        {
            CountryValues.Add(new CascadingDropDownNameValue(
              row["Country"].ToString(), row["IDC"].ToString()));
        }

        return CountryValues.ToArray();
    }

    [WebMethod]
    public CascadingDropDownNameValue[] GetCities(string knownCategoryValues, 
                                                  string category)
    {
        StringDictionary kv = 
          CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);

        //'ContainsKey("Country") is one of property in Ajaxcontroltoolkit
        int countryId;

        countryId = System.Convert.ToInt32(kv["Country"]);

        //ADO.Net
        SqlConnection cn = new SqlConnection();
        DataSet ds = new DataSet();
        DataTable    dt = new DataTable();
        string strCn = 
          "data source=.;Initial Catalog=Db;Integrated Security=True";

        cn.ConnectionString = strCn;
        SqlCommand cmd = new SqlCommand();

        cmd.Connection = cn;
        cmd.CommandType = CommandType.Text;
        //-----I Defined a parameter instead of passing value 
        //     directly to prevent sql injection--------//
        cmd.CommandText = "select * from tblCity where CountryID=@myParameter Order by City";
        cmd.Parameters.AddWithValue("@myParameter", countryId.ToString());
        try
        {
            cn.Open();
            cmd.ExecuteNonQuery();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            da.Fill(ds);
        }
        catch
        {
        }
        finally
        {
            cn.Close();
        }
        dt = ds.Tables[0];

        List<CascadingDropDownNameValue> CityValues = 
                  new List<CascadingDropDownNameValue>();
        foreach (DataRow row   in dt.Rows)
        {
            CityValues.Add(new CascadingDropDownNameValue(
               row["City"].ToString(), row["ID"].ToString()));
        }
        return CityValues.ToArray();
    }
}

GetCountries and GetCities are two functions that get two string arguments: knownCategoryValues and category. They have an output which is an array of strings: CascadingDropDownNameValue. In the GetCountries function, the Country dropdownlist is filled: we connect to the database and execute a query using ADO.NET, then in the foreach loop, fill the dropdownlist. When you select a certain row (in the above example, a country such as United States), knownCategoryValues will be equal to "country:1", which means category is country and knownCategoryValues is "1". 1 is the ID for United States in the database. In the GetCities function, the City dropdownlist is filled and filtered by knownCategoryValues, which is "1" in this case. In the Web Form, I have specified ParentControlID="ddListCountry" in CascadingCity, so the parent is country and the city will be filtered by the country ID. Additionally, I defined a parameter instead of passing value directly, to prevent SQL Injection.

Trying the demo step by step

  1. Go here for .NET 3.5 or here for .NET 4.0 and download the AJAX Control Toolkit file.
  2. Copy the folder "AjaxControlToolkit.Dll" and all its dependencies, they are 18 objects, to your web site in the Bin folder (C:\Cascading\Bin).
  3. Right click on Solution, choose Refresh, then right click again and click Add reference. Then in the Browse tab, double click on the Bin folder and double click on ajaxcontroltoolkit. On the Build menu > click Rebuild.
  4. Create the database and tables like above, and add some rows which have common words.
  5. Create a Web Form and name it CascadingDropDown.aspx. In the HTML view, write some code like above. (This should be exactly like my code because this section is case sensitive.)
  6. Create a Web Service: Solution > right click > Add New Item > Web Service > Name: Cascading.asmx. Language: C# or VB. Go to > App_Code > Cascading.cs or Cascading.vb.
  7. If you are a VB coder, use the VB sample, otherwise use the C# sample.
  8. Run the program, select a country such as United States, and you will see a list of cities in that country such as Detroit or New York City.

Feedback

Feel free to leave any feedback on this article; it is a pleasure to see your opinions and vote about this code. If you have any questions, please do not hesitate to ask me here.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Mahsa Hassankashi
Software Developer
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
Member
I have been working with .Net framework for 7 years.
I`d like to challenge with complex problem, then make it easy for using everyone. This is the best joy.
 
-------------------------------------------------------------
Diamond is nothing except the pieces of the coal which have continued their activities finally they have become Diamond.

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

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionDynamicPopulateExtender,memberMr. Truong Pham27 Mar '13 - 0:34 
QuestionDownloadmemberT Sully21 Apr '12 - 3:57 
GeneralSamething in .net 4.0 and MVC3memberquentininsa19 Jan '12 - 3:09 
GeneralRe: Samething in .net 4.0 and MVC3memberMahsa Hassankashi22 Jan '12 - 13:46 
Questionnice jobmembershaheen_mix31 Dec '11 - 0:53 
AnswerRe: nice jobmemberMahsa Hassankashi31 Dec '11 - 20:32 
BugSQL InjectionmemberMihai Maerean11 Jul '11 - 18:43 
GeneralRe: SQL InjectionmemberMahsa Hassankashi11 Jul '11 - 22:44 
GeneralMy vote of 5memberArlen Navasartian11 Jul '11 - 6:39 
GeneralRe: My vote of 5memberMahsa Hassankashi11 Jul '11 - 12:33 
QuestionGreat Stuffmembercmacd1211 Jul '11 - 5:47 
AnswerRe: Great StuffmemberMahsa Hassankashi11 Jul '11 - 13:18 
Answernice jobmemberalipour200710 Jul '11 - 23:35 
GeneralRe: nice jobmemberMahsa Hassankashi11 Jul '11 - 0:20 
SuggestionGood jobmemberSunasara Imdadhusen10 Jul '11 - 23:10 
GeneralRe: Good jobmemberMahsa Hassankashi11 Jul '11 - 0:18 
GeneralRe: Good jobmemberSunasara Imdadhusen11 Jul '11 - 0:31 
GeneralMy vote of 5memberRhuros10 Jul '11 - 21:51 
GeneralRe: My vote of 5memberMahsa Hassankashi11 Jul '11 - 0:04 
GeneralAnother good one [modified]memberBlue_Boy8 Jul '11 - 0:03 
GeneralRe: Another good onememberMahsa Hassankashi8 Jul '11 - 6:35 
GeneralMy vote of 5membervelsantosh5 Jul '11 - 22:15 
GeneralRe: My vote of 5memberMahsa Hassankashi5 Jul '11 - 23:58 
QuestionMy vote of 5memberAnuj Tripathi28 Jun '11 - 22:43 
AnswerRe: My vote of 5memberMahsa Hassankashi28 Jun '11 - 23:33 
QuestionNice articlememberTohid Azizi28 Jun '11 - 8:10 
AnswerRe: Nice articlememberMahsa Hassankashi28 Jun '11 - 10:49 
QuestionKeep It Up!!!!membergolden.spiral208428 Jun '11 - 3:53 
AnswerRe: Keep It Up!!!!memberMahsa Hassankashi28 Jun '11 - 4:33 
QuestionError when running the applicationmemberwayneh28 Jun '11 - 2:50 
AnswerRe: Error when running the applicationmemberMahsa Hassankashi28 Jun '11 - 4:28 
GeneralRe: Error when running the applicationmemberwayneh29 Jun '11 - 0:47 
GeneralRe: Error when running the applicationmemberMahsa Hassankashi29 Jun '11 - 1:49 
GeneralGreat ;)memberSiavash Mortazavi27 Jun '11 - 22:52 
GeneralRe: Great ;)memberMahsa Hassankashi28 Jun '11 - 3:08 
QuestionQuite impressed! My Vote of 200memberMember 271004227 Jun '11 - 22:30 
AnswerRe: Quite impressed! My Vote of 200memberMahsa Hassankashi28 Jun '11 - 2:58 
QuestionMy vote is 2memberMpho aka Zazo27 Jun '11 - 20:41 
AnswerRe: My vote is 2memberMahsa Hassankashi28 Jun '11 - 4:32 
GeneralMy vote of 5membertusharpal24 Jun '11 - 23:13 
GeneralRe: My vote of 5memberMahsa Hassankashi25 Jun '11 - 2:13 
GeneralMy vote of 5memberFilip D'haene23 Jun '11 - 23:26 
GeneralRe: My vote of 5memberMahsa Hassankashi24 Jun '11 - 2:12 

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130513.1 | Last Updated 12 Jul 2011
Article Copyright 2011 by Mahsa Hassankashi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid