|
|||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThere are often scenarios where we as web developers wish we could provide users the richness and responsiveness of desktop applications. With web applications fast catching up, and also replacing their desktop counterparts, it’s only natural for the users to expect better user experience from the web applications we develop. All of us must have hated the page refresh when we selected a country and then the state drop-down filled based on the country. There are other scenarios such as when we entered the wrong ticket ID on a website and waited for the long submit to render back to our browser only to find out we entered the wrong number, probably a typo. Such dependent drop-downs and server side validations on the website can soon start frustrating the users and force them to look at other websites which do it all on no submit of the page, just like a desktop application did. With businesses fast competing with each other, selling their products on the web and attracting probable customers, the user experience starts taking a primary role. Today, we will take a look at a typical scenario which will demonstrate how a web application can provide better user experience using a set of existing technologies working together, called AJAX. Okay, let us first define AJAX. AJAX – DefinedAJAX stands for Asynchronous JavaScript and XML. AJAX is a term coined by Adaptive Path and is not a new technology. It is a combination of various technologies working in conjunction with each other to provide a rich user experience to web users. AJAX uses:
Let us now try dissecting the term AJAX. A – AsynchronousThis means that this model is different from the Request – Response model associated with conventional web applications. In a conventional web application, the amount of time that elapses between a Request being sent to the server and the Response rendered to the browser can not be essentially put to utilization. The user is working synchronously with the various layers of the application and has an idle time during submits/refreshes. In the AJAX programming model, we can communicate with the business logic and the database layers while the user can still use the browser for doing other controlled [this is up to us to allow what we could allow the user to do during this time] actions. On the whole, this decouples the backend layers and the presentation layer as far as the user is concerned. We may call this as being Apparently Asynchronous. JAX – JavaScript & XMLThis means the Response received from the business logic and the database layer would be represented using XML whose manipulation can be done using JavaScript. JavaScript would also be used for dynamic presentation on the webpage. XML being only a preferred way of communication, the returned Response can even be text which your client side script would understand.
The figure above shows how the AJAX brings with it various advantages we can put to our use in improving the user experience of our websites but at the same time, it also comes with a few disadvantages. Let’s take a look at both: Advantages
Disadvantages
Let us now take a look at the sample application: The Sample ApplicationEmployee-Territory [Northwind Database] dependent dropdown exampleThis application uses a pair Employee – Territory dropdown list. When an Employee is selected from the Employee dropdown, the corresponding territories are loaded into the Territory dropdown. This kind of usage of dependent dropdowns is very common in applications. Conventionally, we have been submitting the page using the We will use the famous Northwind database which ships as a sample database with the SQL Server installation. We consider three tables, Employees, EmployeeTerritories, and Territories having a structure and related to each other as per the following diagram:
Northwind Database Tables EmployeeTerritoryAjaxClient.aspxThe EmployeeTerritoryAjaxClient.aspx is the page that is loaded to the browser. Initially, when the page is loaded, the Employee dropdown is filled on the
EmployeeTerritoryAjaxClient.aspxThe <form id="frmEmployee" method="post" runat="server">
<table border="0" cellpadding="5" cellspacing="0" bgcolor="#ccffff" width="280">
<tr>
<th colspan="2">
AJAX Drop Down Demo</th>
</tr>
<tr>
<td>
<asp:Label id="lblEmployee" runat="server">Select Employee</asp:Label>
</td>
<td>
<asp:DropDownList id="ddEmployee" Runat="server"></asp:DropDownList>
</td>
</tr>
<tr>
<td>
<asp:Label id="lblTerritory" runat="server">Select Territory</asp:Label>
</td>
<td>
<asp:DropDownList id="ddTerritory" runat="server">
<asp:listitem Value="">--Select--</asp:listitem>
</asp:DropDownList>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<asp:Label id="lblStatus" runat="server" class="statustext"></asp:Label>
</td>
</tr>
</table>
</form>
Now, we will look at the code-behind C# code of this page. EmployeeTerritoryAjaxClient.aspx.cs private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack)
{
string connString = ConfigurationSettings.AppSettings["CONN_STRING"];
//Connect to the Northwind Database
SqlConnection connection = new SqlConnection(connString);
connection.Open();
//Build the SQL Query
string SQL = "SELECT EmployeeID, TitleOfCourtesy + ' ' + LastName + ', ' +
FirstName as EmpName FROM Employees";
SqlDataAdapter da = new SqlDataAdapter(SQL, connection);
DataSet ds = new DataSet();
da.Fill(ds);
//Create a DataView with the DefaultView property of the DataSet table
DataView dv = new DataView();
dv = ds.Tables[0].DefaultView;
//Call BindEmployee by passing the created DataView object
BindEmployee(dv);
}
}
BindEmployee Method private void BindEmployee(DataView dv)
{
try
{
if(dv != null) //If DataView is not null
{
ddEmployee.DataSource = dv;
//Text to display in Employee Dropdown
ddEmployee.DataTextField = "EmpName";
//Value to be associated in Employee Dropdown
ddEmployee.DataValueField = "EmployeeID";
ddEmployee.DataBind();
ListItem item = new ListItem("--Select--", "");
ddEmployee.Items.Insert(0, item);
}
else
{
throw new Exception("Dataview is null.");
}
}
catch(Exception ex)
{
Response.Write("Exception: " + ex.Message);
}
}
InitializeComponent Method private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
//Important: Add this statement below to invoke the populateTerritory() JavaScript
this.ddEmployee.Attributes.Add("OnChange", "return populateTerritory();");
}
The One thing to notice here is the following code of the ddEmployee.Attributes.Add("OnChange", "return populateTerritory()");
where we add the JavaScript functions: <script language="javascript">
var request;
var response;
var Territory = document.getElementById("ddTerritory");
var status = document.getElementById("lblStatus"); function populateTerritory()
{
var Employee = document.getElementById("ddEmployee");
if(Employee.options[Employee.selectedIndex].value != '')
//Check if the selectedItem is not "--Select--"
{
return SendRequest(Employee.options[Employee.selectedIndex].value);
}
else
{
clearSelect(Territory);//Clear the Territory dropdown
status.innerText = "";//Blank the status text label
}
} function InitializeRequest()
{
try
{
request = new ActiveXObject("Microsoft.XMLHTTP");
//Try creating an XMLHTTP Object
}
catch(Ex)
{
try
{
//First failure, try again creating an XMLHTTP Object
request = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(Ex)
{
//Else assign null to request
request = null;
}
}
if(!request&&typeof XMLHttpRequest != 'undefined')
{
request = new XMLHttpRequest();
}
} function SendRequest(ID)
{
status.innerText = "Loading.....";//Set the status to "Loading....."
InitializeRequest();//Call InitializeRequest to set request object
//Create the url to send the request to
var url = "EmployeeTerritoryAjaxServer.aspx?EmployeeID="+ID;
//Delegate ProcessRequest to onreadystatechange property so
//it gets called for every change in readyState value
request.onreadystatechange = ProcessRequest;
request.open("GET", url, true);//Open a GET request to the URL
request.send(null);//Send the request with a null body.
} function ProcessRequest()
{
if(request.readyState == 4)
//If the readyState is in the "Ready" state
{
if(request.status == 200)
//If the returned status code was 200.
//Everything was OK.
{
if(request.responseText != "")
//If responseText is not blank
{
//Call the populateList fucntion
populateList(request.responseText);
//Set the status to "Territories Loaded"
status.innerText = "Territories Loaded";
}
else
{
//Set the status to "None Found"
status.innerText = "None Found";
//Call clearSelect function
clearSelect(Territory);
}
}
}
return true;//return
} function populateList(response)
{
//Create the XMLDOM object
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
//Load the responseText into the XMLDOM document
xmlDoc.loadXML(response);
var opt;
//Create the EmployeeTerritories element
var TerritoriesElem =
xmlDoc.getElementsByTagName("EmployeeTerritories");
//Create the TERRITORIES element
var TerritoryElem =
TerritoriesElem[0].getElementsByTagName("TERRITORIES");
clearSelect(Territory);
//Clear the dropdown before filling it with new values
if(TerritoriesElem.length > 0)
//If there are one or more TERRITORIES nodes
{
for (var i = 0; i < TerritoryElem.length; i++)
//Loop through the XML TERRITORIES nodes
{
//Create a TextNode
var textNode = document.createTextNode(
TerritoryElem[i].getAttribute("TERRITORYDESCRIPTION"));
//Call appendToSelect to append the text
//elements to the Territory dropdown
appendToSelect(Territory,
TerritoryElem[i].getAttribute("TERRITORYID"), textNode);
}
}
} function appendToSelect(select, value, content)
{
var opt;
//Create an Element of type option
opt = document.createElement("option");
//Set the option's value
opt.value = value;
//Attach the text content to the option
opt.appendChild(content);
//Append the option to the referenced [Territory] select box
select.appendChild(opt);
} function clearSelect(select)
{
//Set the select box's length to 1
//so only "--Select--" is available in the selection on calling this function.
select.options.length = 1;
//You may want to write your own clearSelect logic
}
</script>
There are three JavaScript global variables:
Let us now take a look at the EmployeeTerritoryAjaxServer.aspx page. This page essentially contains only the Here is the code-behind C# code of the EmployeeTerritoryAjaxServer.aspx page: EmployeeTerritoryAjaxServer.aspx.cs private void Page_Load(object sender, System.EventArgs e)
{
string ID = Request["EmployeeID"];
if(ValidateID(ID))
{
if(ID.Trim() != "" && ID != null)
{
try
{
SqlConnection conn = new
SqlConnection(ConfigurationSettings.AppSettings["CONN_STRING"]);
//Connect to the Northwind Database
conn.Open();
SqlCommand command =
new SqlCommand("SELECT TERRITORYID, RTrim(TERRITORYDESCRIPTION) as" +
"TERRITORYDESCRIPTION FROM TERRITORIES WHERE TERRITORYID IN" +
"(SELECT TERRITORYID FROM EMPLOYEETERRITORIES WHERE EMPLOYEEID="
+ ID + ") for xml auto", conn);
//Execute the SqlCommand Object
SqlDataReader dr = command.ExecuteReader();
System.Text.StringBuilder sbXML =
new System.Text.StringBuilder();
if(dr.HasRows)
{
while(dr.Read())
{
sbXML.Append(dr.GetString(0).Trim());
}
//Set the ContentType of the Response Object to "text/xml"
Response.ContentType = "text/xml";
//Response.Write the XML generated
//by appending <EmployeeTerritories> tag on
//both ends of the XML string to create a documentElement
Response.Write("<EmployeeTerritories>" +
sbXML.ToString() + "</EmployeeTerritories>");
}
else
{
//Response.Write an empty string so your client script
//understands no response was returned
Response.Write("");
}
}
catch
{
//Response.Write an empty string so your client script
//understands no response was returned
Response.Write("");
}
}
else
{
//Response.Write an empty string so your client script
//understands no response was returned
Response.Write("");
}
}
}
Page_Load EventThe ValidateID method private bool ValidateID(string ID)
{
for(int Count=0;Count<ID.Length;Count++)
{
if (!System.Char.IsNumber(ID, Count))
//Check if the input ID value is numeric
{
return false;
}
}
return true;
}
The Executing Sample CodeBefore running the sample application, you will need to create a virtual directory of the AJAXDropDown folder inside the AJAX___ASPNET folder after unzipping. Also, make sure that you have an instance of SQL Server 2000 available and you have the Northwind database in that. Open the solution in Visual Studio and modify the following element in your web.config file. <add key="CONN_STRING" value="data source=<your data source here >;
Database=northwind;User=<user name>;PWD=<password>"/>
Build the application before running it. Try selecting an employee, you will see the Territory dropdown filling with the corresponding territories as in the figure below:
SummaryIn this article, we discussed about AJAX and how it can be used in a web application to improve user experience. We also saw how we saved on the amount of data being transmitted over the network by sending the response as XML and not the whole rendering HTML code. There are various such applications which can benefit by using AJAX. At the same time, it is up to us to decide where we want to make use of this concept depending on various factors viz., security, environment, performance etc. I would like to thank my colleague Rashmi Ramachandra for making those diagrams you saw earlier in the article. I hope this made an interesting reading for you. You can send me your comments at srinivas.alagarsamy@gmail.com. Thank you!! | ||||||||||||||||||||||||||||||||