Have Your DOM and Script It Too
When working with the XMLHttpRequest
object it appears you can only go one of three ways:
- You can stay true to the colorful moniker du jour and stick strictly to the
responseXML
property - You can play with proprietary – yet widely supported – fire and inject the value of responseText property into the
innerHTML
of an element of your choosing - Or you can be eval() and parse JSON or arbitrary JavaScript delivered via
responseText
But did you know that there’s a fourth option giving you the best of the latter two worlds? Mint uses this unmentioned approach to grab fresh HTML and run arbitrary JavaScript simultaneously. Without relying on eval()
. “But wait-”, you might say, “when would I need to do this?” Besides the example below this technique is handy for things like tab groups that need initialization onload
but miss the main onload
event handler by a mile thanks to asynchronous scripting.
Consider the problem
Originally Mint used option 2 to refresh or load new tabs into individual Pepper panes without requiring a full roundtrip to the server. This was all well and good until I introduced the new Client Mode which when enabled allows anyone to view a Mint installation without being logged in. If voyeurs are afoot as Client Mode is disabled, the next time they refresh a pane the entire login page is inserted into the current document. That’s not very helpful so I needed a way to redirect the current document to the login page.
Enter the solution
Wouldn’t it be cool if browsers interpreted the contents of script tags crammed into innerHTML
? Sure, but unfortunately, that just wasn’t meant to be. However like the body element, image elements have an onload event handler. When the image has fully loaded the handler runs the code applied to it. See where I’m going with this?
By tacking a tiny image (think single pixel, transparent spacer gif – shudder) onto the end of the HTML returned by our Ajax call, we can smuggle our arbitrary JavaScript into the existing document. The image is added to the DOM, and our stowaway can go to town.
<p>This is the results of our Ajax call.</p>
<img src="../images/loaded.gif" alt="" onload="alert('Now that I have your attention...');" />
Please be neat
So we’ve just jammed some meaningless cruft into our DOM. If our script does anything with images this addition could have some unexpected side effects. (Remember The Fly?) So in order to save that poor, unsuspecting element whose innerHTML
we just swapped out from sharing Jeff Goldblum’s terrible fate we should tidy up after ourselves. And by using the removeChild
method we do just that.
<p>This is the results of our Ajax call.</p>
<img src="../images/loaded.gif" alt=""
onload="alert('Now that I have your attention...');this.parentNode.removeChild(this);" />
About the author
Shaun Inman designed and developed Mint, the curiously successful web site analytic tool. He passes the time (literally) tinkering on ShaunInman.com while nervously eyeing the dust gathering on Designologue.