Ajax Redux - the development of an open API
find
index | search | post | contact
Topics
General
Introduction
About this blog
Wish List


More Links
Post and comments
Technique defined
Technique advocated
Browser share stats

Progressive Enhancement example

Intro | Step 1 | Step 2 | Step 3: The XMLHttpRequest enhancement

The XMLHttpRequest method is easier to develop with, and a bit nicer on the user too, so we add it next. Again, this layer just goes on top of the other ones, so that if it fails for whatever reason, one of the lower layers will catch it. In our case, the new layer is just an enhancement to sendChangeRequest:


Billy Ray was a preacher's son

See the highlighted additions in the code below. We try to create an XMLHttpRequest, and if we fail, the iframe functionality kicks in. Works about the same anyway, right? You may notice this page's widget doesn't mess with your back button the way the last page did, but that's a small difference. However, our form is pretty simple. If we were using more of the features of the XMLHttpRequest object (or if more features get developed in the near future), then the iframe trick might not handle them, and there would be a greater difference between differently abled browsers.

<script language="javascript">

function showForm() {
    document.getElementById('view').style.display = 'none';
    document.getElementById('form').style.display = 'block';
    return true;
}
function showView() {
    document.getElementById('form').style.display = 'none';
    document.getElementById('view').style.display = 'block';
    return true;
}

function sendChangeRequest(form) {
var req = null; try { req = new ActiveXObject("Msxml2.XMLHTTP"); } catch (exc) { try { req = new ActiveXObject("Microsoft.XMLHTTP"); } catch (exc2) { } } if (req == null && typeof XMLHttpRequest != "undefined") { req = new XMLHttpRequest(); } if (req != null) { var url = "edit.html?billyray=" + escape(form.billyray.value); req.onreadystatechange = function() { if (req.readyState == 4) { var endIndex = req.responseText.indexOf(";"); var result = req.responseText.substring(0, endIndex); receive(document, result); } } req.open("GET", url); req.send(null); } else { // No XMLHttpRequest; try iframe request
form.target = "iframe_receive"; form.submit();
}
return true; } function receive(targetDocument, result) { formElement = targetDocument.getElementById('form'); var newText = targetDocument.createTextNode(formElement.billyray.value); var linkElement = targetDocument.getElementById("link"); linkElement.removeChild(linkElement.firstChild); linkElement.appendChild(newText); showView(); alert(result); } </script> <div id="view" class="data" style="display:block"> Billy Ray was a <a href="staticForm.php" id="link" onclick="javascript:return ! showForm();">preacher's son</a> </div> <form action="edit.html" id="form" class="form" style="display:none"> onsubmit="javascript:return ! sendChangeRequest(this);"> <span>Billy Ray was a </span> <input type="text" name="billyray" value="preacher's son" /> <input type="submit" value="Save changes" onclick="javascript:return ! sendChangeRequest(this.form);" /> <input type="button" value="Don't change" onclick="javascript:return ! showView();" /> </form> <iframe name="iframe_receive" src="../0.html" style="width:0px; height:0px; border: 0px"></iframe>

You may want to see the source of "edit.html", which is our server-side script. In the real world, of course, it wouldn't be a static HTML file; it'd produce a result based on input. Here's the file that's standing in for a real script:

and when his daddy would visit he'd come along; <!-- XMLHttpRequest method -->
<script language="javascript"><!-- for iframe scripting method -->
    window.top.receive(window.top.document,
        "and when his daddy would visit he'd come along");
</script>

Yep, we put both the iframe response and the XMLHttpRequest response in the same file. You don't have to do that; you could call two different server-side scripts, or pass an argument specifying which type of response you want. But your server does have to handle both types of responses. If your server architecture is decent, this shouldn't be much trouble.

< Step 2: The Javascript handler | Blog entry and comments: Why this should be easier >