Wednesday, August 06, 2008

Synchronizing client requests using Ajax

Before few months I was dealing with a problem where I needed to synchronize the server call sequence on browser. The problem was something like this: Client code will open new window navigating to a different page, but that should happen only after post on current page. The link that new window was opening needed to be server synchronized because of database updates etc. on server.

Being ignorant java-script developer I went ahead and put 'window.open' in onsubmit event of submit button, hoping it will be executed before form is submitted; Apparently, it failed. The event handling/dispatching/capturing in java-script is in sad state - it's specific to browser and I must make it work for IE so the pain is obvious. To reveal some more ignorance, I thought of putting 'window.open' in onmousedown event assuming form will not be submitted till the code in onmousedown is executed
fully, that too failed. Then, it was clear that 'window.open' was essentially a thread fork and will execute in parallel so this event capturing is not going to work here.

Since there was no obvious fix to my problem, I thought of using XMLHTTP for asynchronous wait to synchronize the request. I created new page which will open in a new window with javascript that handles form post in parent window, looks like following:
<html>

<body onload="postParentWindow()">
<%
out.print("Loading Print Preview, Please wait...");
%>
</body>
</html>


getFormValues is a function which concatenates all the input's selected values and makes a request string. More interesting things are done in makePOSTRequest method:
var http_request = false;
function makePOSTRequest(url, parameters) {
http_request = false;
try {
http_request = newActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
http_request.onreadystatechange = navigateToOtherPage;
http_request.open('POST', url, true);
http_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http_request.setRequestHeader("Content-length", parameters.length);
http_request.setRequestHeader("Connection", "close");
http_request.send(parameters);
}

function navigateToOtherPage() {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
window.navigate('newpage.jsf');
} else {
alert('There was a problem with the request.');

}
}

(Note: This code completely disregards browser compatibility and good error handling etc.) The important thing here is, we can assign a function to XMLHTTP object that will be executed after server response is received so that serves my purpose of synchronizing the request. I find this use of AJAX pretty useful in building stateful web-applications. The code might look very crude but powerful abstractions can be built over it to make a nice utility framework for such use-cases.

2 comments:

Ramesh said...

Hi,
You could check out jQuery's BlockUI lib. Use jQuery's AJAX API to get some nifty ajax functionality;abstract off most of the http_request and get some great ajax experience.It has very good cross-browser support.
Using the XMLHttpRequest object in synchronous mode causes the entire browser to lock until the remote call completes. This is usually not a desirable behavior[ref]
-- Ramesh

Nirav Thaker said...

Hey Ramesh,

I didn't know we can use XMLHttpRequest in synchronous mode as well. As far is this post is concerned I'm not using synchronous calls. Thanks for the links, I will check them out.