Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Accessing Html Document Content in other Frames


:P
On this page:

Here’s a question that I see pop up quite frequently on newsgroups: How do I access content across frames or an iFrame using JavaScript code? It’s actually quite easy once you understand how the windowing mechanism in the browser works.

Imagine you have two pages – one that holds an iFrame and another that holds the content for the iFrame. Both the host page and the iFrame contain a <div id=”message”> tag that is used to write some content into the other frame.

Here’s the top level page:      

    <div class="errordisplay" id="message">
       original
   </div>


   <iframe src="FramesPage2.aspx" id="frame1" height="400">
   </iframe>    
   
    
   <script type="text/javascript">
       window.onload = function() {
           var frame = document.getElementById("frame1");
           var msg = frame.contentDocument.getElementById("message");
           msg.innerHTML = "Hello World from Frame Page 1";
       };    
   </script>

And here the iFrames source page that gets loaded into the iFrame:

<div class="errordisplay" id="message">
original
</div>

<script type="text/javascript">        
        var msg = window.parent.document.getElementById("message");
        msg.innerHTML = "Updated from iFrame";    
</script>

The above works both with iFrames, Frames or separate windows that were loaded from the current window.

From the top level window that contains the iFrame you start by getting a reference to the iFrame by using plain old getElementById to select the iFrame by Id. Alternately you can also access the frame via window.frames[0] (or appropriate numeric index). Once the iFrame is selected you can use the contentDocument property to access the child frame content. From there you can access document methods as you normally would – in this case by using getElementById() and then assigning some HTML to the display <div> tag in the child frame.

In the child frame to reference back to the parent frame is easier yet: You can use the window.parent property to get a reference to the parent frame. You can then simply reference the document and continue on accessing elements in the parent document.

Cross Frame Functions

The previous code is  - ahem - functional, but realistically accessing cross frame elements is probably not something you should do extensively. When you control elements in another browser window you are stuck with directly coding against the DOM – using libraries like jQuery for example isn’t possible since tools like it work against content in the current window.

If your interaction is any more complex that say grabbing or setting a single value , it’s probably better to create functions in the target frame and call these functions across the frame border rather than the individual DOM commands individually. That way you can encapsulate the functionality in the child page, which makes it easier to code and test the functionality, and it also allows you to use any libraries the way you normally would. You can then simply call the function from the parent page to perform more complex tasks indirectly.

To call a function across frames is fairly easy. Assume that the iFrame code I showed earlier also includes a function called showMessage in script code that updates it’s internal message <div> tag like this:

    <script type="text/javascript">
            function showMessage(m) {
                document.getElementById("message").innerHTML = m;
            }
    </script>

To call this function from the parent frame you can use a couple of approaches. The easiest is to use the frames collection:

<script type="text/javascript">
    window.onload = function() {
        window.frames[0].showMessage("Hello from Main Page in iFrame");
    };    
</script>  

The individual frame is essentially a reference to the window object in the child frame and all global JavaScript functions are functions off the window object. So you can directly call the function of the frame. Easy. The main issue with this that you need to know (or find) the frame index first.

You can also get it through the frame DOM element in the parent page and use its contentWindow property to get at the child window:

<script type="text/javascript">
    window.onload = function() {
        var frame = document.getElementById("frame1");
        var win =  frame.contentWindow;
        win.showMessage("Hello from Main Page in iFrame");
    };    
</script>

and this works as well.

With the abillity to call functions it’s much easier to offload processing to other frames more efficiently which allows for creation of self contained modules that let you interact with only a few small interface points. For example, you can create window objects that load content dynamically and yet act independently  and without interfering with each other.

Posted in JavaScript  

The Voices of Reason


 

Grant Barrington
January 06, 2009

# re: Accessing Html Document Content in other Frames

Hi Rick,

Just so you are aware, the method you've suggested above only works when the iframe picks up content from the same domain as the page hosting the iframe.

In your example above, if you had <iframe src="http://google.com" />, you cannot manipulate the content (or even get the properties).

We had an site that was going to host pages from a sub-domain in our site. We were going to use javascript to re-size the iframe based on the content so it looked as if the iframe was actually part of the page. As soon as it came from a sub-domain, you could not get access to any of the document properties of the iframe. It did work if the page src was from the original domain.

Regards,
Grant

Tek
January 07, 2009

# re: Accessing Html Document Content in other Frames

@grant It is to prevent Cross Site Scripting, also known as XSS. It is a good thing, it prevents websites that hosts adds (for example) to access user entered data shared by Javascript on the current website visited by the user.

Ken Davis
January 08, 2009

# re: Accessing Html Document Content in other Frames

@grant

It is possible to communicate between pages from sub-domains by modifying the
document.domain property.

Look at http://blogs.msdn.com/dthorpe/archive/2007/09/27/cross-domain-communication-using-domain-lowering.aspx

Josh Stodola
January 08, 2009

# re: Accessing Html Document Content in other Frames

Just to add a little to the discussion going here with the comments...

Everyone is correct, you cannot access anything in the frame if the contents are not sitting on the same domain as the parent. I am working on something right now at my job where we transfer to a banking application provided by our bank that handles credit card and echeck transactions. To keep them disconnected from our site while they were on the banking application, I wrote a "lightbox" style modal iframe. This banking application allows me to set a URL to redirect the user to when their transaction completed. The application also has an Exit/Cancel button that I also can set.

While I was unable to access the frame while the user was on the banking application, I still was able to control it immediately before and immediately after they were done. The initial page in the iframe sits on our server. It has a "Please wait..." message and automatically submits a form to this banking application onload. When they are done, they are redirected to a landing page on our server, where the necessary Javascript can safely be executed to close the lightbox. In my case, after closing the lightbox I programmatically did a postback with Javascript to do execute some server-side code a redirect them accordingly. It works real slick.

I just wanted to add this to let everyone know that you can still create an elegant and seamless transition to another application (from your application) using just Javascript and iframes. What's important is making sure the other application is capable of redirecting back to a landing page on your server.

Regards...

Josh Stodola
January 08, 2009

# re: Accessing Html Document Content in other Frames

My bad, you already mentioned that. LOL, I got lost in the middle of the post. Please delete <grin>

Ran Davidovitz
January 08, 2009

# re: Accessing Html Document Content in other Frames

There are lot of methods that enable you do cross document communication:
1. location.hash - Using hash property - see http://tagneto.blogspot.com/2006/06/cross-domain-frame-communication-with.html
2. window.name - see http://www.sitepen.com/blog/2008/07/22/windowname-transport/
3. Proxying the site in the same domain (bad design)
4. Inline scripts (can work on another domains) - and start using fully client centric operations(e.g script render and handled data and GUI) - This is hard.
5. flash local connection - see http://livedocs.adobe.com/flex/2/langref/flash/net/LocalConnection.html
6. and there are more like this

FYI - IE solves this by using new method of cross document messaging - see http://msdn.microsoft.com/en-us/library/cc511311(VS.85).aspx

Also don't forget that when running under IE you might not see cookies in the iframe because you are considered as 3rd party domain the solution is to add P3P headers to your site or be at Local intranet or Trusted zones see MSDN article - http://support.microsoft.com/kb/293222/)

More over guess you already know it but IFRAME are not XHTML 1.1 compliant, alternative is using OBJECT element.

lastly i would like to suggest reading a very nice research from Microsoft about the cross domain communication and solutions at http://research.microsoft.com/en-us/um/people/helenw/papers/subspace.pdf

Andrew D
January 09, 2009

# re: Accessing Html Document Content in other Frames

Good post. Although we've all done a few variations on this area in the past it's nice to see them collated and clarified in one place.

Grant A
January 12, 2009

# re: Accessing Html Document Content in other Frames

The problem is of course that:
1) location.hash isn't exactly elegant
2) window.name - looks like a giant hack
3) Proxying the site in the same domain - not ideal agreed
4) Inline scripts - great idea, but doesn't solve the problem of cross-domain scripting with a site that's not your own!
5) Flash local connection - same problem

Ultimately we have to face facts and admit that there are some things browsers just weren't designed to do - cross site scripting was designed to protect page content and therefore I'd say it's doing its job.

Ben
January 12, 2009

# re: Accessing Html Document Content in other Frames

There's also a technique that allows a degree of interaction between windows or fames hosted on different domains without any common sub-domain. This is referred to as "on demand" or "dynamic" javascript. Essentially you are loading javascript from a different domain that is created dynamically - for instance via an asp.net page. This javascript is loaded via a script tag in the header of the parent page and is immediately executed. The result of this execution can do anything you want - update the UI, do an AJAX postback, whatever.

Some links explaining this technique
http://rockstargirl.org/sandbox/bidynodes/
http://ajaxpatterns.org/On-Demand_Javascript#Technical_Story

It can be very useful in certain real-world scenarios, such as a catalog control/page on a central site that several related sites load, and is known to work on IE, Firefox, and WebKit (Safari/iPhone/gPhone/Palm Pre).

Crescent Fresh
January 13, 2009

# re: Accessing Html Document Content in other Frames

For the DOM purists out there, you can use iframe.contentDocument.defaultView instead of iframe.contentWindow.

iframe.contentWindow has better support though.

Josh Stodola
February 03, 2009

# re: Accessing Html Document Content in other Frames

I discovered today that not only do the pages need to reside on the same domain, but they need to be accessed via the same protocol (HTTPS or HTTP) as the parent.

Wendy
November 14, 2009

# re: Accessing Html Document Content in other Frames

Hi,

I tried the code first posted and it does what I want it to do in FireFox and Safari, but IE 8, when run from the server, gives me an error at the bottom of the browser window (doesnt' say what the error is, just that little yellow triangle and "error on page".) Funny thing is if I open the parent file in IE 8 locally, it works fine. Also tried uploading to a different server, and it works fine in IE. Does anyone know how I can tell my server to allow IE 8 to use this javascript code? (maybe with an .htaccess file?)

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024