AjaxPatterns
This is the original book draft version for the IFrame Call Ajax pattern, offered for historical purposes and as an anti-spam measure.
You're probably better off visiting the Live Wiki Version for IFrame Call instead, where you can make changes and see what others have written.

IFrame Call

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

Goal Story

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.

Problem

How can the browser communicate with the server?

Forces

Refer to "Forces" for “XMLHttpRequest Call”.

Solution

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.

Figure 1.9. Posting a form via IFrame Call

Posting a form via IFrame Call

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.

Real-World Examples

Google Maps

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”).

Figure 1.10. Google Maps

Google Maps

Scoop Framework, Kuro5hin

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.

Figure 1.11. Kuro5hin

Kuro5hin

PXL8 Demo

Michele Tranquilli has an excellent tutorial on IFrames with embedded examples.

HTMLHttpRequest Library

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”.

Code Refactoring [AjaxPatterns Sum Demo]

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.

Alternatives

“XMLHttpRequest Call” is the natural alternative to IFrame Call. The Alternatives section of that pattern compares the two approaches.

Frame Call

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).

Metaphor

A hidden IFrame is like having an invisible friend you can delegate queries to.

Live Wiki Version for IFrame Call