Imagine, you are working on a webshop.
Imagine further, that you have a page displaying the users shoppingcart. Left of each entry, there’s an <input type="text"> for letting the use change the quantity of the article. Till now quite a common scenario, isn’t it?
Now in the time of DHTML and all that, you write some JavaScript to automatically recalculate the grand total of your shoppingcart on-the-fly, as the user is changing the quantities. This is very nice, as the user gets immediate response to her actions. No reloading the page is involved.
Now imagine further that the user has changed quite some quantities. The new cart is nothing like the old one was. The user is very happy with the total recalulating itself on every key she presses while the focus is in one of those editfieds. Very nice.
Now the user realizes that she needs another product. She clicks on the “Browse”-Link and …
What happens?
Well,… the link certainly works and she browses around in the shop looking for another product to order. But there’s a serious problem lurking around: As all the calculations were done on the client when the user changed the quantities, the server knows nothing about the changes. The server still thinks (provided something like a HTTP-Session-Emulation being at work – but how would you implement a shopping-cart without it?) the quantities are unchanged. When the user looks at the cart the next time (even after reloading the cart-page), she will see all the old values.
How to fix this? (Jonas, if you read this entry: This is about the solution to a problem we faced about a year ago while working on PopScan SMB). Most common today is one of the following:
- Post the form on every change of the quantity. While this fixes the problem, it’s not very convinient for the user – especially if she uses a slow modem link. And even if the link is fast: Reloading the page whenever I’m tabbing out of an edit-field is very disturbing (though I’ve seen sites where the page even reloads on every key press).
- Don’t recalculate anything, but provide an “Update values”-Button. This is what most users are used to as this is how the web worked so far: You enter something, you submit it to the server or you lose it.
Now this is where XMLHTTP comes to play.
While it has XML in it’s name, it has very less to do with XML. It’s a technology to send HTTP-Requests from JavaScript. And not only that: The requests are sent completely transparent to the end-user in the background. She doesn’t notice the slightest thing while the script is posting requests. As the API is asynchronous, there even is no waiting involved – not even over slow lines.
So.. how does it work?
I used this function to post back quantity-changes from my shoppingcart:
function updateToServer(quant,art){
var xmlhttp=false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
// JScript gives us Conditional compilation, we can cope
// with old IE versions and security blocked creation of
// the objects.
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
xmlhttp = false;
}
}
@end @*/
if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
xmlhttp = new XMLHttpRequest();
}
xmlhttp.open("GET", "/index.php/order/qchg?a="+encodeURI(art)+
"&q="+encodeURI(quant),true);
/* not interested in feedback. if it doesn't work, too bad. other
methods provide fallback
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
alert(xmlhttp.responseText)
}
}*/
xmlhttp.send(null)
}
(disclaimer: much of the code comes from this page. If you know, what you are doing, copy&paste really is a timesaver.)
What does it do?
- It uses some IE-trickery with conditional code to instantiate the object.
- If the IE-code does not get run (on every standards-compliant browser), it uses the common way to instantiate the thing
- It prepares the request
- It sets up some event-handlers. As I’m not interested in the outcome, I’m not setting up anything.
As you can see, I created a special url for accessing my shop-system, just for updating the quantities.
This function is called from the onChange-event of the quantity-change-input-boxes. Now, whenever the user changes a quantity, /index.php/order/qchg is called, advising the server to update the quantity (if you find the URL strange – using PATH_INFO and all that: I will post something about a PHP-design-pattern that I’m using that has proven to be the most powerful in all those years I’ve been working with PHP).
Problem solved.
And just 30 minutes after implementing this method, I found out that for the purpose I’m using it, this whole XMLHTTP-thing would not be necessary:
While some trickery with FRAMEs could do the same thing, the really best method that even works with Netscape 4.x (even 3.x, if I remember correctly) would be to conditionally change the URL of a (transparent 1px2) image. This works always if no feedback from the script must be evaluated:
Pseudocode:
function updateToServer(quant, art){
document.images['qposter'].src="/index.php/order/qchg?a="+encodeURI(art)+
"&q="+encodeURI(quant);
}
A one-liner, no frame-trickery (frames are bad – even for such things), no finding out what object to instantiate, no problems with near-browsers,… very nice, but nowhere near structural markup, which is why I prefer the less hacky solution.
I hope, this was helpful for you. And as I’m progressing with this very interesting project I’m working on, I certianly will have more of such things to post.