Client Side Validation Using the XMLHTTPRequest Object

By Jonathan Zufi

As an avid reader of 15 seconds, I've been exposed to many articles on form validation. Form validation should not only address checking fields for content and structure, it should also handle real-time lookups on data. This article shows how Microsoft's XMLHTTPRequest component can give your users a cleaner and more efficient Web experience by improving form validation.

Programming for HTTP

There have always been several ways of making HTTP calls on the Win32 platform. Visual Basic and C++ developers could leverage the WinInet library, and Visual Basic programmers could utilize the Internet Controls that shipped with Visual Basic 6.0. However, ASP developers have had a bit more work getting access to this functionality, since they would need to wrap it in a custom component for elegant interaction with ASP code. 'Raw' scripting makes the task difficult.

Most people assume HTTP is a protocol reserved for browsers to communicate with Web servers. Remember, HTTP is just a protocol, and a powerful one at that. HTTP can be used by any application to talk to another application or component; it doesn't have to be a browser or a Web server. As Web developers, we are all familiar with the benefits of using the HTTP protocol. It works well across firewalls, is based on Internet standards, etc.

Microsoft included the XMLHTTPRequest component in its XML toolkit so XML documents could be passed around over the Internet using the standard HTTP protocol. While all the documentation speaks of XML interchange over HTTP, the nice thing about this component is that you don't have to deal with XML at all to leverage its power. Only a few lines of code are necessary to make a HTTP call and capture the results. This makes the XMLHTTPRequest component an extremely powerful tool in every Web developer's arsenal, especially ASP developers.

XMLHTTPRequest and XMLHTTP

The XMLHTTPRequest component is part of MSXML, which ships with Internet Explorer 5.0 and higher. This makes it an even more attractive tool. The core object inside XMLHTTPRequest is the XMLHTTP object. There are different versions of the XMLHTTP object, since it's been included in every version of the Microsoft MSXML package. For a good overview of the latest versions and installation issues, see the Microsoft knowledge base article Q278969.

The XMLHTTP object provides all of your Web browser's communication functionality with just a handful of methods and properties. To use this object, create the XMLHTTP object, call the open method with the URL you want to talk to, the type of call to make (GET, POST), and then invoke the send method. The object will basically act like a browser and retrieve the data from the URL, making it available in the responseText property. You can also make synchronous or asynchronous calls. There is also a callback facility available for asynchronous calls. Very neat and very simple.

Using XMLHTTP to perform real time data validation

Say that you are capturing user registration details for your Web site, and one of the fields is 'User ID'. This User ID obviously needs to be unique across your site, so you'll have a requirement to ensure that the User ID supplied at registration time does not already exist. If it does, you'll need to warn the user and ask them to re-enter it.

The common way of dealing with this type of requirement is to apply the lookup logic when the form is posted. However, this can sometimes lead to what is not the best user experience. We all know how frustrating it is to continually submit forms only to find that we have forgotten a value here or there. The other downside of posting the page is that if it needs to be re-rendered with the appropriate 'please correct this problem' messages, that's another trip to the server, images, script and all.

The ideal way to handle this is to alert users as soon as they have entered their username as to whether or not it is unique. On a desktop app, this would be simple - put some code in the 'lost focus' event of the text box. Javascript and the XMLHTTP object can provide the same level of interaction.

Let's walk through an example, registering with a fictitious company.

The HTML for the User ID field looks like this:


<input type="text" name="UserID" onblur="validateuserid(this.value);">


The 'onblur' event will fire our validation routine when the user tabs out of the User ID textbox. (Note: if you're not a fan of focus driven validation, you could move this to the onclick event of the Register button).

Examine the JavaScript that performs the validation:


<SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript">
function validateuserid(suserid) {

document.body.style.cursor='wait';

// Create an instance of the XML HTTP Request object
var oXMLHTTP = new ActiveXObject( "Microsoft.XMLHTTP" );
	
// Prepare the XMLHTTP object for a HTTP POST to our validation ASP page
var sURL = "http://mysite/mypath/validateuser.asp?username=" + suserid
oXMLHTTP.open( "POST", sURL, false );

// Execute the request
oXMLHTTP.send();

if (oXMLHTTP.responseText == "exists") 
alert("Sorry - the User ID " + suserid + " already exists.");

document.body.style.cursor='auto';
}
</SCRIPT>

Let's go through the script block in detail to see what its doing:


document.body.style.cursor='wait';

The script is going to make a HTTP call, which might take a second or two, so this line changes the mouse to an hourglass to give the user some feedback. From the user experience point of view, there are prettier things you can do with the UI other than changing the mouse pointer. Javascript and DHTML give you everything you need. In fact, there is a much more elegant way to handle this, which we'll examine later on.

// Create an instance of the XML HTTP Request object
var oXMLHTTP = new ActiveXObject( "Microsoft.XMLHTTP" );

This creates an instance of the XMLHTTP object.

	// Prepare the XMLHTTP object for a HTTP POST to our validation ASP page
var sURL = "http://mysite/mypath/validateuser.asp?userid=" + suserid
oXMLHTTP.open( "GET", sURL, false );

The 'open' method prepares the request that we are about to make. The first parameter defines the connection to use. In this case, we'll use the GET method. 'open' supports other methods such as PUT and POST. (POST is VERY powerful, because as implied, you can programmatically post forms as well). The next parameter specifies the URL that we are connecting to. Since we are running this script on the client, this should be an absolute URL. Here we construct a call to a custom ASP page which will tell us whether or not the User ID exists (more on this in a moment).

The third parameter is used to tell the object whether or not to make the call asynchronously. I've set this to False, indicating that we want to wait until the call returns before continuing.

There are two other optional parameters, username and password. These allow a connection to a site that requires username/password authentication.

Now that we have prepared the request, we just need to send it.


// Execute the request
objXMLReq.send();

At this point the object will actually go out over the Internet and bring back the contents of the target page. Now we check those contents to see what happened:

if (objXMLReq.responseText == "exists") 
			alert("Sorry - the User ID " + suserid + " already exists.");

If the User ID has already been assigned to another user, the page returns the word 'exists' to indicate that the user id already exists in the database. (You could use any protocol you like - for example, the ASP page could have returned a number.) Finally we reset the cursor.

document.body.style.cursor='auto';

Now let's look at the ASP page that the script is communicating with to do the lookup:

<%
Dim objConn, objRS, sUserID

'Capture the username that we need to lookup, making sure its prepared for 
'our forthcoming SQL query
sUserID = Replace(Trim(Request.QueryString("userid")),"'","")	

'Fire up ADO - ask the database whether or not the user idexists
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open CONNECTIONSTRING
sSQL = "select userid from usertable where userid = '" + sUserID + "'"
Set objRS = objConn.Execute(sSQL)
If Not objRS.EOF Then Response.Write "exists"   

'Clean up
objRS.Close
objConn.Close
Set objRS = Nothing
Set objConn = Nothing
%>

This is a straightforward piece of ASP code that writes out the word 'exists' if the passed-in User ID was found in the database. If you ran this page on its own, the browser would be blank if the User ID did not exist -- the page would just say the word 'exists' if it did exist. This means that you can test your ASP page in isolation before you integrate it back with your client script.

Dealing with timeouts

The first issue that has probably crossed your mind is 'what if the remote site is down - how do I handle timeouts and errors?' While trapping an error from the 'send' method is feasible, this doesn't fix the time the user would have to wait while the call is being made.

Recall the third parameter on the 'open' method of the XMLHTTP object. We set it to 'false'. Setting it to 'true' will make the call immediately, and the control will drop through to the next line, so you need to either poll or be notified (i.e. event) that the call has completed (successfully or not). Luckily, the XMLHTTP object can notify the function of your choice as it moves through its various stage of processing the HTTP request. Let's have a look at a slightly modified version of the client side script that deals with potential timeouts:


<!-define a div that will be our pseudo progress indicator -->
<div id="divProgress">Please wait</div>

<SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript">
// Create an instance of the XML HTTP Request object
var oXMLHTTP = new ActiveXObject( "Microsoft.XMLHTTP" );
var userid;	
function validateuserid(suserid) {
	
// Prepare the XMLHTTP object for a HTTP POST to our validation ASP page
userid = suserid;
var sURL = " http://mysite/mypath/validateuser.asp?userid=" + userid;
oXMLHTTP.open( "POST", sURL, false );
	
// Define an event handler for processing
oXMLHTTP.onreadystatechange = managestatechange;
	
// Execute the request
try {
	oXMLHTTP.send();
}
catch (e) {
	alert("Could not validate your User ID at this time.");
	document.all.item("FirstName").focus;
}
}

function managestatechange() {
switch (oXMLHTTP.readyState) {
	
case 2, 3:
			// Display a progress indicator of some kind, informing the
// user that you are checking to see if the UserID exists
document.all.item("divProgress").style.display = "block";
break;
	
		case 4:
	if (oXMLHTTP.responseText == "exists") 
				alert("Sorry - the User ID " + userid + " already exists.");
	document.all.item("divProgress").style.display = "none";
			break;
}	
}

// Hide the progress indicator for now
document.all.item("divProgress").style.display = "none";

</script>
 
The code of interest here is line where we set the event handler:

// Define an event handler for processing
oXMLHTTP.onreadystatechange = managestatechange;

This tells the XMLHTTP object to call the 'managestatechange' function as it the state of the HTTP request changes - from the time the object is created until the point where the request has completed. There are five different states that you can monitor:

0 (UNINITIALIZED) The object has been created, but not initialized (open method has not been called).
(1) LOADING The object has been created, but the send method has not been called.
(2) LOADED The send method has been called and the status and headers are available, but the response is not yet available.
(3) INTERACTIVE Some data has been received. You can call responseBody and responseText to get the current partial results.
(4) COMPLETED All the data has been received, and the complete data is available in responseBody and responseText.

- from MSDN

In the updated script, I also make it a little more robust by adding some error handling. After all, the remote site may be down or the page may not exist:


// Execute the request
try {
	oXMLHTTP.send();
}
catch (e) {
	alert("Could not validate your User ID at this time.");
	document.all.item("FirstName").focus;
}

When the code in the callback function is finished, the control will return to the calling routine, and if a problem occurred, you can cater for it. Note that I set the focus to another field. This is important, otherwise the user would never be able to move out of the User ID field.

It is useful to note at this stage that there is another component called the ServerXMLHTTP object - see the Microsoft knowledge base article Q290761 for details about the differences between these two components. ServerXMLHTTP, as the name implies, is more suited for HTTP connectivity from the server end and is a little more elegant when dealing with timeouts. This is useful to know if you want to do some bigger and better things. This article was focused on client side validation so we focused on the XMLHTTP object since it was actually designed and optimized to be a client side component.

I hope this article has shown you how powerful the XMLHTTPRequest object from Microsoft is. Check out the MSDN Web site for more examples.

About the Author

Jonathan Zufi is the founder of UDU World (http://www.uduworld.com), a company that sells solutions based on their ActiveInbox technology. ActiveInbox is a back end information and content delivery platform that provides information access over email and mobile text messaging.

Jonathan has been developing software for over ten years. He holds an Honour's degree in Robotics and Digital Technology from Monash University (Melbourne, Australia). He was recently awarded the Pearcey Award from the Australia Computer Society, which recognizes innovative and pioneering achievement and contribution to research and development in Information and Computer Technology across Australia. Jonathan may be reached at jonathanzufi@UDUworld.com



Comments

  • POST GET

    Posted by Vladimir on 11/14/2014 06:36pm

    In the first script there is a typo: it should be oXMLHTTP.open( "GET", sURL, false ) instead of oXMLHTTP.open( "POST", sURL, false ), isn't it? Actually it is so in further consideration.

    Reply
  • let me try this with php!

    Posted by Isabelle Simard de Cabrera on 10/05/2012 05:42pm

    Focus on client, I like it! I was thinking how to use XMLHttpRequest asyncronously in a form where I need consulting MySQL database for few things before sending de form. You help me so much with that really great post! Let me try this now with php-MySQL... so cool! If working well, I´ll send the code, Tanks!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • Hundreds of millions of users have adopted public cloud storage solutions to satisfy their Private Online File Sharing and Collaboration (OFS) needs. With new headlines on cloud privacy issues appearing almost daily, the need to explore private alternatives has never been stronger. Join ESG Senior Analyst Terri McClure and Connected Data in this on-demand webinar to take a look at the business drivers behind OFS adoption, how organizations can benefit from on-premise deployments, and emerging private OFS …

Most Popular Programming Stories

More for Developers

RSS Feeds