Iframe reloads when moved around the DOM tree

I had a great idea. And to implement it, I needed to do DOM manipulation of an element that contains an IFRAME. It’s simple right? Just do something like

document.getElementById(“to”).appendChild(document.getElementById(“elementwithiframe”));

This actually worked. It even works if the iframe is generated using document.write that is part of an external javascript. I was almost done with my project. When I was testing out another javascript that creates an iframe, I ran into the first issue. The elementwithiframe moved by the iframe was blank.

I observed that in one case the javascript creates an iframe that has the src attribute and loads the iframe content from a URL. In another case, it creates the iframe and opens the iframe’s document and writes the content and closes the iframe. The second case is where I had the problem. This happens in both Firefox and Safari.

I wasted a lot of time on this issue. I even came up with a workaround for the second case. The workaround is to first get the head and body elements of the iframe before it’s moved and after the move, copy it back. In fact it worked perfectly fine. But I was still curious why the behavior is different in both case. I even downloaded WebKit source and browsed through it, didn’t find the exact issue, but the dom API has it’s issue which I will tell in a few minutes.

Then, after searching on Bugzilla@Mozilla, I found a bug that gave more details. Apparently, when an iframe is moved around the DOM tree, it’s refreshed. So, if an iframe has an src element, it’s just refreshing the frame again. This means the document is loaded twice. But when the iframe is created by opening the document and writing the content, that content is lost when the DOM is moved. It doesn’t seem to execute the script again (which is probably what is desired as otherwise, there would then be two frames). More importantly, the script element that generated the iframe should not execute the second time because the iframe is generated using document.write. So, once a document is loaded, calling document.write can have unwanted consequences. Anyway, I wasn’t observing this, so hopefully moving script element with src attribute around doesn’t execute it again.

Net net, moving an iframe around the DOM model makes it refresh and in case where the document content is filled using javascript, the iframe is going to lose it’s content unless the hack I mentioned above is done.

Looking at the above Mozilla bug and also the WebKit code I looked at made me realize that part of the problem is with DOM specification which states that since a node can have only one parent, moving around requires removing the node from the parent and then adding it back. But to remove the node, usual logic used is removeNode api. So, in case of an iframe element, calling the removeNode seems to have the adverse impact of clearing up the content (why this happens only for iframe but not other types of elements like div beats me, but may be that has to do with the fact that iframe represents a complete document altogether and not cleaning up immediately when the removeNode is called can have memory issues).

Had the apis to move the node (appendChild, insertBefore, insertAfter) were not required to do the remove as per the spec, then this would have been a simple move without destroying the iframe content. But again, I don’t know if I should say that the DOM api is wrong because as I mentioned, this works for other types of elements, not just iframe.

The fact that this bug was filed on 2004-08-03 and it’s open to this day reflects the complexity of fixing this issue which I don’t hope anytime soon. Someone actually provided a patch in 2009, but it’s not incorporated yet because of concerns on what it might break in several other areas.

After giving this some more thought, I abandoned my project which I thought I got a master idea :).

Advertisements

3 Comments

Filed under DOM API, IFRAME, javascript

3 responses to “Iframe reloads when moved around the DOM tree

  1. I’m sure this was probably more of a “proof of concept” project, but, I have to ask… why would you WANT to use a iframes? 🙂

    In a world capable of scraping (it’s gotten so much easier in the last few years) and with all of the AJAX libraries available, why not just save yourself the headaches iframes can cause on the SEO front and use those? XAJAX (decent support) and jQuery (amazing support/community) are SO easy to implement. Sure, there will be those odd-ball jobs where you have a hack to implement, but, mainly what I’ve run into is CSS stuff.

    XAJAX is great for doing heredoc-type content & structure changes… jQuery is freaking great for GUI stuff.

    I just loath iframes… I guess, knowing what it’s application would be is what’s hanging me up here. 🙂

    My interest is definitely peaked, though. Snippets?

    • S

      Hi, yes, I wouldn’t use iframes unnecessarily. AJAX and DOM manipulation are the way to go. However, here the javascript files that create these iframes are not within my control.

      Just to be clear, there are times when iframes should be used. This is for security purpose. Otherwise, the content that’s fetched remotely and injected into the main page can be malicious. Or vice versa, where you are not supposed to trigger events in the content that’s fetched separately. A great example is Ads. If the ad code is part of the main page, then web masters can start generating a lot of revenue by triggering events from javascript.

      Up until now, the iframes are strictly secure based on the origin of their content. But I beleive, in HTML5, there are element attributes that can control the behavior. So, if there are two websites that trust each other, then they can bypass the cross domain script security issue. I think so, I haven’t gone too much into technical details yet.

      • +1 for ya, there. (ad revenue)

        Sandbox attribute will be interesting to see… Seamless could be scary with all of the event handler attributes now being available… but, for you [this project] might open the door to a solution.

        You should revisit this with HTML5 standards in mind. (when time permits)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s