
Call, Callback, Download, Frame, IFrame, Live, Query, Remoting, RemoteScripting, Upload

Bill's ordering a car online and the price is always synchronised with his choice. This happens because of a hidden IFrame. Each time he changes something, the browser populates a form in the IFrame and submits it. The IFrame soon contains the new price, which the browser copies into the visible display. XMLHttpRequest could have accomplished the feat too, but it's not supported in Bill's outdated browser.
Refer to "Forces" for “XMLHttpRequest Call”.
Use IFrames for browser-server communication. Much of the fuss in Ajax concerns the XMLHttpRequest object, but sometimes other remoting techniques are more appropriate, and IFrame Call is one of those (see the Alternatives section of “XMLHttpRequest Call” for a comparison). IFrames are page-like elements that can be embedded in other pages. They have their own source URL, distinct from their parent page, and the source URL can change dynamically. IFrame Calls work by making the IFrame point to a URL we're interested in, then reading the IFrame's contents once the new content has loaded. Note: An online demo illustrates most of the code concepts throughout this Solution and the code snippets loosely follow from the demo.
To begin with, you need an IFrame in the initial HTML, and an event handler registered to catch
the onload event. (It would be less obtrusive to register the handler with Javascript,
but due to certain browser "features", that doesn't always work.)
<iframe id='iFrame' onload='onIFrameLoad();'></iframe>
We're using the IFrame as a data repository, not as a user-interface, so some CSS is used to hide it. (The more natural choice would be
display: none, but as
an experimental demo shows,
browser strangeness makes it infeasible.)
#iFrame {
visibility: hidden;
height: 1px;
}
On the server, we're initially going to use the web service discussed in
“XMLHttpRequest Call”:
sumGet.phtml. To call the service, we'll change the IFrame's source:
$("iFrame").src = "sumGet.phtml?figure1=5&figure2=1";
We already registered an
onload handler in the initial HTML. The handler will be called when the new content
has loaded, and at that stage, the IFrame's body will reflect the content we're after. The following
code calls a function,
extractIFrameBody(), which extracts the body in a portable manner (based on
http://developer.apple.com/internet/webcontent/iframe.html).
function onIFrameLoad() {
var serverResponse = extractIFrameBody($("iFrame")).innerHTML;
$("response").innerHTML = serverResponse;
}
That covers the GET call. To illustrate POSTing, we'll invoke the
sumPost.phtml service, also discussed in
“XMLHttpRequest Call”. POST calls are a bit more complicated because we
can't just change the source. Instead, we dynamically inject a form into the IFrame and submit it. In
this example, the arguments ('5' and '2') are hard-coded, but they could easily be scripted by manipulating
the input elements.
var iFrameBody = extractIFrameBody($("iFrame"));
iFrameBody.innerHTML =
"<form action='sumPostForm.phtml' method='POST'>" +
"<input type='text' name='figure1' value='5'>" +
"<input type='text' name='figure2' value='2'>" +
"</form>";
var form = iFrameBody.firstChild;
form.submit();
As with conventional form submission, the IFrame will be refreshed with
the output of the form recipient. Thus, the previous
onLoad handler will work fine.
Figure 1.9, “Posting a form via IFrame Call” illustrates the overall process.
Another approach with IFrames is to have the server output some Javascript which alters the parent,
or calls a function defined in the parent. The code will automatically be called when the page loads,
so there's no need for an
onload handler. Unfortunately, this approach creates substantial coupling between
the server and browser. In contrast, note how the examples above used completely generic web services
- the services only know how to add numbers together and nothing about the calling context. That's possible
because all behaviour was encapsulated in the
onload() function.
As “Call Tracking” discusses, there are problems - and suitable workarounds - with simultaneous “XMLHttpRequest Call”s, and the same is true for IFrames. First, you need to create a separate IFrame for each parallel call - you don't want to change an IFrame's source while it's waiting for a response. Second, you need to investigate and test limitations, because the application can grind to a halt if too many calls are outstanding.
There's one last problem with IFrame Call: Browser UIs aren't really built with this application in mind, so some things might seem funny to users. In particular, Alex Russell has pointed out two issues that arise with IFrame Calls under IE : the "phantom click" and the "throbber of doom". The former repeats a clicking sound every time an IFrame request takes place and the latter keeps animating the throbber icon while the IFrame is loading. These devices are great for a full page refresh, like when you click on a link, but they suck when a script is trying to quietly talk with the server behind the scenes. In Alex's article, he explains how he unearthed a fantastic hack inside GMail's chat application. The hack suppresses the annoying behaviour by embedding the IFrame inside an obscure ActiveX component called "htmlfile", which is basically a separate web page. As the IFrame isn't directly on the web page anymore, IE no longer clicks and throbs. See Alex's blog post for full details.
Make no mistake: IFrame Call is a pure hack. IFrames were never intended to facilitate browser-server communication. It's likely the technique will slowly fade away as XMLHttpRequest gains popularity and as legacy browsers are retired. Nevertheless, it does retain a few advantages over “XMLHttpRequest Call”, mentioned in the Alternatives section of that pattern.
Google Maps, perhaps the most famous Ajax App, lets you navigate through a map of the world (Figure 1.10, “Google Maps”). Location and metadata is required from the server, and this content is retrieved using IFrames. Google also uses XMLHttpRequest, for downloading XSLT stylesheets (a technique described in “Browser-Side XSLT”).
Scoop, an open-source content management system, uses IFrames for discussion areas (Figure 1.11, “Kuro5hin”). Using the "dynamic comments" module, users can drill down a discussion thread without reloading the whole page. Scoop powers the popular Kuro5hin website among other sites.
Michele Tranquilli has an excellent tutorial on IFrames with embedded examples.
Angus Turnbull's HTMLHttpRequest is a portable Web Remoting library that initially attempts to use XMLHttpRequest, and if that fails, falls back to IFrame. The tool is documented in the Code Examples section of “Cross-Browser Component”.
The Basic Sum Demo uses XMLHttpRequest, and there's a version available that's been refactored to use IFrame. There's no walkthrough here as it's very similar to the GET component of the demo discussed in the Solution above.
“XMLHttpRequest Call” is the natural alternative to IFrame Call. The Alternatives section of that pattern compares the two approaches.
Before IFrames, there were plain old frames. As a user-interface concept, they've had a few public relations problems over the years, but they do at least provide a means of remote scripting similar to IFrame Calls (even if it was accidental). Since IFrames are now widely supported, it's unlikely you'll ever need to use frames for remote scripting (or anything else, for that matter).