The sample application uses a pair of DropDownList controls. A change in the selected value of the first drop-down list should populate the second drop-down list with a new collection of items. This paired behavior is found in many applications, such as a Country-State pair and a Category-Product pair. We have chosen to discuss the Country-State DropDownList pair. In traditional web applications, a change in the value of the Country DropDownList results in the web page posting back to server in order to populate the States DropDownList. In our example, we will populate the States DropDownList by retrieving state data from the server using AJAX, without submitting the entire form to the server.
In this section, first we will discuss the CountriesAndStates.xml and CountriesAndStates.xsl files, and then the CountryStateXml class which is used to get country and state data from the XML file. Next, we will discuss the start page of our project, which is AjaxClient.aspx. We will then discuss our JavaScript files, AjaxVariables.js and AjaxScript.js. You will find core AJAX code in the AjaxScript.js file. Finally we will talk about the AjaxServer.aspx page, which handles the AJAX requests.
CountriesAndStates XML and XSL Files
The CountriesAndStates.xml file stores the names of all countries and their states. The format of this XML file is shown below (Listing 2). Each country is represented as a single country node, and all of its states are represented as child nodes. At present this XML file has only three countries and some of the states of these countries. You can edit this XML to add other countries and states.
Listing 2 – CountriesAndStates.xml File
<country name="USA">
<state>Alabama</state>
<state>Alaska</state>
<state>Arizona</state>
<state>Arkansas</state>
</country>
The CountriesAndStates.xsl file has the transformation logic for converting one form of XML into another form of XML. This transformation takes a country name as an input parameter, and returns its corresponding states in an XML string.
CountryStateXml class
The CountryStateXml class is used to get country or state data in different formats depending on the method called. This class has one constructor and three public methods. The constructor loads the CountriesAndStates.xml file into an XPathDocument. The public method GetCountryList returns a list of countries as an ArrayList. The second method GetStateList returns a list of states for a given country as an ArrayList. The third method GetStatesXMLString returns an XML document containing all the states for a given country name, along with the country name.
AjaxClient Page
The start page of our sample application is AjaxClient.aspx and Figure 1 shows it viewed in a browser. This page has two DropDownList server controls. The HTML markup of this page is given in Listing 3. The onchange event of the Country DropDownList is tied to the JavaScript function CountryListOnChange and is shown in bold text in the following markup. We will discuss the CountryListOnChange function later in this section.
Figure 1 – AjaxClient.aspx Page in a Browser
Listing 3 – HTML of AjaxClient.aspx page
<form id="Form1" method="post" runat="server">
<asp:DropDownList id="countryList" onchange="return CountryListOnChange()"
style="Z-INDEX: 101; LEFT: 20px; POSITION: absolute; TOP: 28px"
runat="server" Width="174px" Height="28px"></asp:DropDownList>
<asp:DropDownList id="stateList"
style="Z-INDEX: 102; LEFT: 218px; POSITION: absolute; TOP: 28px"
runat="server" Width="174px"></asp:DropDownList>
</form>
Listing 4 shows the code for the Page_Load method of this web page. When the page loads for the first time, this method populates the Country and State DropDownList controls using the GetCountryList and GetStateList methods of CountryStateXml class.
Listing 4 – Page_Load Method of AjaxClient.aspx Page
private void Page_Load(object sender, System.EventArgs e)
{
CountryStateXml countryStateXml = new CountryStateXml();
ArrayList countries = countryStateXml.GetCountryList();
for(int index = 0; index < countries.Count; index++)
{
countryList.Items.Add(countries[index].ToString());
}
ArrayList states = countryStateXml.GetStateList(countries[0].ToString()) ;
for(int index = 0; index < states.Count; index++)
{
stateList.Items.Add(states[index].ToString());
}
}
JavaScript Code
The AjaxScript.js file includes the required AJAX script. When the selected value of the country drop-down list changes, the CountryListOnChange function is called. Now we will talk about how the asynchronous request to the server in the CountryListOnChange function works. See Listing 5.
-
Form the request URL with the selected country in the query string.
-
The CreateXmlHttp function (this function is explained in the earlier section, Creating an Instance of an XMLHTTPRequest Object) creates an instance of an XMLHTTP request object. If the browser does not support the XMLHTTP object, the XmlHttp variable will be set to null and the AJAX code will not be executed. If the browser supports the XMLHTTP object, an asynchronous request is submitted to the server using the XMLHTTP object.
-
The onreadystatechange property of the XMLHTTP object is used to set the response handler for the asynchronous request. This response handler gets called for every change of readyState property of the XMLHTTP object. In our code we set the HandleResponse function as the response handler.
-
The open method is called to initialize the request. The first parameter of the open method takes a method definition (GET, POST, etc.), in our case it’s GET. The second parameter takes the request URL. The third parameter takes a Boolean value indicating whether the request submitted is synchronous or asynchronous. In our sample it’s asynchronous, so the third parameter is set to true. Other parameters are optional; we do not use them in our application.
-
The send method submits the request to the server. The send method's behavior is determined by the third parameter of the open method. In our case it is true, so the send function behaves as an asynchronous function, which means that the browser calls the send function and does not wait for the response to come back from the server.
Listing 5 – CountryListOnChange Function
function CountryListOnChange()
{
var countryList = document.getElementById("countryList");
var selectedCountry = countryList.options[countryList.selectedIndex].value;
var requestUrl = AjaxServerPageName + "?SelectedCountry="
+ encodeURIComponent(selectedCountry);
CreateXmlHttp();
if(XmlHttp)
{
XmlHttp.onreadystatechange = HandleResponse;
XmlHttp.open("GET", requestUrl, true);
XmlHttp.send(null);
}
}
When the response comes back from the server, the HandleResponse function (Listing 6) gets called. In fact, the HandleResponse function is called for every change of the readyState property of the XMLHTTP object. The readyState property can take a value from 0 to 4 (0=UNINITIALIZED, 1=LOADING, 2=LOADED, 3=INTERACTIVE, 4=COMPLETED). A value of 4 (i.e., COMPLETED) means that receiving the response from the server is completed and the response data is available through properties of the XMLHTTP object. For the readyState property to reach the value of 4, this property changes the value four times (i.e., from LOADING to COMPLETED), so the HandleResponse function gets called four times for each response. To make sure that the data is available in the XMLHTTP object, the XmlHttp.readyState property is compared to the value of 4 in the HandleResponse function (Listing 6).
If the readyState of the XMLHTTP instance has a value of 4, we then need to check its status property to make sure that a valid response was received. The status property holds the HTTP status code returned from the server. A value of 200 means that data received in the request is OK. Some of the other popular HTTP status codes, with which most developers are familiar, are 404 (page not found), 403 (access forbidden), and 500 (internal server error). We check that the XmlHttp.status property is 200 to make sure that the response received has a status of OK. The responseXML property of the XMLHTTP object returns an XML document. This property is useful only when the response from the server is in XML format. In our sample, the response is a list of states in XML format. If both conditions are satisfied (readyState is 4 and status is 200), we call the function ClearAndSetStateListItems with the XML document as an input parameter.
Listing 6 – HandleResponse Function
function HandleResponse()
{
if(XmlHttp.readyState == 4)
{
if(XmlHttp.status == 200)
{
ClearAndSetStateListItems(XmlHttp.responseXML.documentElement);
}
else
{
alert("There was a problem retrieving data from the server." );
}
}
}
The function ClearAndSetStateListItems clears the items in the State DropDownList and populates this drop-down list with the new states list by traversing through the XML document supplied as input.
AjaxServer Page
The AjaxServer.aspx file will handle the request sent by the client-side JavaScript using the XMLHTTPRequest object. This page does not have any GUI elements. Listing 7 shows the Page_Load event handler of the AjaxServer.aspx page. This method gets the selected country name from the query string, retrieves the state names as an XML document, and then writes the XML document into the response object.
Listing 7 – Page_Load Method of the AjaxServer.aspx Page
private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack )
{
string selectedCountry = Request["SelectedCountry"];
if(selectedCountry.Length > 0)
{
Response.Clear();
CountryStateXml countryStateXml = new CountryStateXml();
string statesString = countryStateXml.GetStatesXMLString(selectedCountry);
Response.Clear();
Response.ContentType ="text/xml";
Response.Write(statesString);
Response.End();
}
else
{
//clears the response written into the buffer and end the response.
Response.Clear();
Response.End();
}
}
else
{
//clears the response written into the buffer and end the response.
Response.Clear();
Response.End();
}
}
Running Sample Code
After downloading the sample application as a Zip file, extract its contents to your wwwroot directory. Create a virtual directory in IIS with the name AjaxSample, and map it to the extracted AjaxSample folder. Using Visual Studio, open the AjaxSample.sln file and press F5 to run the application.