IFrame Call - Ajax Patterns

IFrame Call

From Ajax Patterns

Evidence: 1/3

Tags: Call Callback Download Frame IFrame Live Query Remoting RemoteScripting Upload



Contents

In A Blink

Diagram: Circle from page (button trigger) to script to server to iframe to script to body


Goal Story

Stuart's ordering a car online and the price is always synchronised to reflect 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.


Problem

How can the browser communicate with the server?


Forces

Refer to "Forces" for XMLHttpRequest.


Solution

Use IFrames for browser-server communication. 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 when the new content has loaded.

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 frame as a data repository, not as a user-interface, so some CSS is used to hide the frame. (The more natural choice would be display: none, but as an experimental demo shows, browser strangeness makes it infeasible.)

 #iFrame {
   display     : none;
   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 [1]).

 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.

Alternatively, one can set the target attribute of a HTMLFormElement to the name of the iframe, which causes the form to be submited to iframe, while the page that contains the form remains unchanged.

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 Calls, 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.

Make no mistake: IFrame Call is a pure hack. IFrames were never created to facilitate browser-server communication. It's likely the technique will slowly fade away as XMLHttpRequest gains popularity and as older browsers are replaced. Nevertheless, it does retain a couple of advantages over XMLHttpRequest Call, as discussed in the Alternatives section of that pattern.



Online references are made to XMLHttpRequest Call: for sumGet.phtml and sumPost.phtml. However there is no sumPost.phtml in the online version. The book on page 109 refers to a sumPost.phtml in section XMLHttpRequest Call: but unfortunately it is not there. The closest to it, on page 97, is a file called "sumPostForm.php". I'm too new here to know if there is an errata of some sort. Perhaps somebody could fix this and do the appropriate followup.


I'm not sure what the function "extractIFrameBody" does. I did a google search and only find this string on your site. I follow the link to apple and there's nothing about it there. Perhaps the function could be copied to this site?


Sorry for the confusion. I don't have the details to hand, but I'd say sumPost.phtml was refactored from sumPostForm.php, so they are likely the same file. extractIFrameBody is specific to the AjaxPatterns code, so you won't find it as a generic function on Google. I think you'll find it in the lib/php directory - try a recursive grep (grep -R /ajaxpatterns/path extractIFrameBody --Mahemoff 07:07, 6 December 2006 (EST)


If you want to access the body of the iframe object you can do it this way (I'm assuming the "extractIFrameBody" method does something similar):

   var iFrameBody = document.getElementById("iFrame").contentWindow.document.body;
   iFrameBody.innerHTML = "whatever html code you want";

--124.120.185.115 03:40, 9 March 2007 (EST)

Decisions


Real-World Examples

Google Maps

Google Maps, perhaps the most famous Ajax application, lets you navigate through a map of the world. Panning and zooming require Web Remoting in order to grab new image and location data from the server, and all of this uses IFrames. It's not clear why, but Google also use XMLHttpRequest, for downloading XSLT stylesheets (a technique described in Browser-Side XSLT). link title

PXL8 Demo

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

JSRS

Brent Ashley's JSRS is a Web Remoting library based on IFrames. It's of interest as perhaps the earliest Web Remoting framework, with the initial version having been released back in 2000 and continues to be used today. A basic demo is also available.

HTMLHttpRequest

Angus Turnbull's HTMLHttpRequest is another Web Remoting library. It checks if XMLHttpRequest is supported, and if not, falls back to IFrame. The tool is documented in the Code Examples section of Cross-Browser Component.


Refactoring Illustration

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

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


Related Patterns


Visual Metaphor

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


Want to Know More?