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: The Javascript handler | Step 3

Next we're going to add a layer of javascript that makes the form appear and disappear, and which also redirects the form so that it fetches a script from the server and runs it. This is your standard iframe script hack, and is supposed to work in all standard javascript-enabled browsers. But you might also want to try using the form with javascript turned off in your browser.


Billy Ray was a preacher's son

The code is below, with additions highlighted. Note that the onclick function of the hyperlink returns false if the sendChangeRequest function returns true, and vice versa. onclick only aborts the loading of the new page if sendChangeRequest runs and returns false, which is what would happen in a fully functional browser.

<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) { form.target = "iframe_receive"; form.submit(); return true; } // our response tasks: swap the link text, hide form again, pop up alert 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 element brought directly into this page
<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"
<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>

If javascript isn't enabled, onclick and onsubmit are ignored entirely. But you get an extra failover bonus, because if anything goes wrong in showForm or sendChangeRequest, then onclick or onsubmit will return true, and the link will be loaded as if there were no javascript.

The iframe hack works because the server's response is a script which sends the result to this page's receive function. receive then processes the result. It has the (usually undesirable) effect of taking up a slot in the browser history (try your back button). Frankly, you could leave out the iframe part if you're going to add XMLHttpRequest in the next step. But then anyone without ActiveX/XMLHttpRequest would miss out on the benefits of your javascripted interface. And I've included it here to illustrate that you can pile up multiple layers of enhancement.

Maybe you noticed I'm not a big fan of detecting the browser type in advance (I call it indirect stereotyping). That method gets quickly obsolete, and doesn't catch all errors anyway. What we're doing here is more robust: we add a layer that tries to do a new trick. If the new trick fails, we allow the code to simply fall through to the layer below, which is less prone to fail. We know that the bottom layer works with all browsers, so we should be okay.

< Step 1: The universal form | Step 3: The XMLHttpRequest enhancement >