65.9K
CodeProject 正在变化。 阅读更多。
Home

AJAX 入门(第二部分)- 使用 XMLHttpRequest 和 jQuery AJAX 实现级联下拉列表

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (37投票s)

2012 年 6 月 12 日

CPOL

6分钟阅读

viewsIcon

229762

downloadIcon

5592

本文讨论了在 ASP.NET 应用程序中使用 XMLHttpRequest 和 jQuery AJAX。

这个迷你系列共有三篇文章

引言

本文讨论了 ASP.NET 应用程序使用 XMLHttpRequest 对象和 jQuery AJAX 实现异步功能(即 AJAX)的各种方法。

背景

在本系列的第一部分(Part 1)中,我们了解了 ASP.NET 开发人员在 Web 应用程序中实现 AJAX 功能的各种方法。我们还了解了如何使用 ASP.NET AJAX 服务器控件。现在,本文将重点介绍使用 XMLHttpReuqest 对象和 jQuery AJAX 在 Web 应用程序中实现异步行为。

XMLHttpObject 可以在后台促进客户端和服务器之间的数据交换,也就是说,使用 XMLHttpObject 可以实现部分页面更新。

jQuery 是一个 JavaScript 框架,它使开发人员能够轻松完成许多客户端工作。jQuery AJAX 是一组例程,可在后台提供客户端和服务器之间的通信,从而实现部分页面更新。

Using the Code

在本文中,我们将尝试解决许多开发人员经常遇到的一个常见问题。我们将尝试使用 AJAX 实现级联下拉列表。我们将首先使用 XMLHttpObject 实现此功能,然后使用 jQuery AJAX 实现。

在开始处理手头的问题之前,让我们先了解一下解决方案和所需的功能。假设我们有一个数据库,其中包含所有大陆和国家/地区的列表。用户将看到两个下拉列表。第一个下拉列表将包含大陆列表,当用户从该列表中选择任何大陆时,第二个下拉列表应异步更新,即无需导致任何回发。

ajax article 2 images

让我们看一下包含大陆和国家/地区列表的数据库表以及其中包含的数据。

ajax article 2 images

注意:数据库没有经过任何优化或规范化,因为这并非本文的重点。

现在,我们有一个负责所有数据库通信的辅助类。理想情况下,此类应作为数据访问层的独立解决方案存在,但为简化起见,我创建了这个类。

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;
    }
}

此类将有助于检索大陆列表以及特定于该大陆的国家/地区列表。现在让我们开始处理实际问题。

使用 XMLHttpObject

让我们创建一个包含两个下拉列表的页面(default.aspx)。我们将第一个下拉列表初始化为第一个大陆名称,将第二个下拉列表初始化为该大陆的国家/地区。然后,我们将使用 XMLHttpObject 根据用户对第一个下拉列表的选择来更改第二个下拉列表的内容。此页面的代码隐藏将仅包含 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();
    }
}

现在,我们要做的下一件事是在客户端处理第一个下拉列表的 onchange 事件。

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

现在,要使用 XMLHttpObject 根据用户选择获取国家/地区列表,我们需要执行以下操作:

  1. 创建 XmlHttpObject
  2. 检索用户当前对第一个下拉列表的选择。
  3. 使用 XMLHttpObject 将此值通过查询字符串传递给服务器上的网页。
  4. 处理我们刚刚进行的异步请求的响应。
  5. 检索响应中的值。
  6. 根据响应中找到的新值更改第二个下拉列表项。

上述算法中需要注意的重要一点是,我们需要一个页面来处理此异步请求,提取查询字符串,然后将结果推送到响应中。让我们为此目的创建一个名为 frmForAjaxCalls.aspx 的页面并实现该功能。

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();
        }
    }
}

现在,唯一剩下的就是客户端 JavaScript 代码,它将使用 XMLHttpObject 调用此页面。以下代码将显示如何完成。

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)
    {
        //everything so far is just fine, let's proceed
        
        //Retrieve 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 found 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);
            }
        }
    }
}

现在,当我们运行此页面时,我们可以看到第一个下拉列表中的选择将触发与服务器的异步通信,第二个下拉列表将用该大陆的国家/地区的值填充。所有这些都是在没有任何服务器回发的情况下完成的。

使用 jQuery AJAX

让我们创建一个类似的页面,其中包含两个下拉列表(default2.aspx)。我们将第一个下拉列表初始化为第一个大陆名称,将第二个下拉列表初始化为该大陆的国家/地区。然后,我们将使用 jQuery AJAX 根据用户对第一个下拉列表的选择来更改第二个下拉列表的内容。此页面的代码隐藏将包含 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();
    }
}

现在,与 XMLHttpObject 不同,如果我们使用 jQuery,则无需创建另一个页面来处理异步请求。我们可以在 asme 页面中创建一个 static 函数(或者,如果需要,也可以创建一个单独的页面),该函数将接受一些参数并返回一些值。将参数传递给此函数、调用此函数以及处理结果将是客户端上 jQuery 的职责。让我们看看这个函数。

[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;
}

static 函数还应使用 WebMethod 属性进行装饰。这表明此方法将从客户端调用。

注意:具有 WebMethod 属性的此 static 方法可以被视为一个小型 Web 服务,可以使用此页面的 URL 从客户端访问。

现在,要使用 jQuery AJAX 根据用户选择获取国家/地区列表,我们需要执行以下操作:

  1. 处理第一个下拉列表的 onchange 事件。
  2. 检索用户当前对第一个下拉列表的选择。
  3. 创建一个 JSON 对象以将此数据传递到服务器。
  4. 指定要调用的页面/方法名称。
  5. 处理响应回调。
  6. 检索响应中的值。
  7. 根据响应中找到的新值更改第二个下拉列表项。

以下代码将显示如何使用 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 found 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);
            }
          }
       });
   });
});

现在,当我们运行此页面时,我们可以看到第一个下拉列表中的选择将触发与服务器的异步通信,第二个下拉列表将用该大陆的国家/地区的值填充。所有这些都是在没有任何服务器回发的情况下完成的。

关注点

我们已经了解了在 ASP.NET 网站中实现 AJAX 行为的两种方法。第一种方法是使用 XMLHttpObject,第二种方法是使用 jQuery AJAX。我们仅对这两种方法进行了初步了解,以了解如何完成。这两种方法都有许多可自定义的选项,可以实现对异步通信的更好控制。我建议我们详细阅读这两种方法。这将有助于更好地理解事物。

我们还解决了开发人员(尤其是新手)经常遇到的一个常见问题,即创建级联下拉列表。本文介绍了两种实现方法。我们还可以使用 AJAX 控件工具包来实现此功能以及更多 AJAX 功能。但这也许需要另行讨论。

历史

  • 2012年6月12日:初版
© . All rights reserved.