Inject Content into a new IFrame

In on-line ad delivery we utilize the <iframe> tag quite a lot. There are good reasons for serving ads in iframes. There are restrictions in communication between an iframe and its parent window when the two documents are served from different domains. This helps protect users as well as site publishers from malicious activity.

Iframes also provide advantages in the speed of delivery of an overall page. The parsing and display of an iframe’s content happens asynchronously to the rest of the parent window’s resources. This means that when an iframe is encountered during an initial page load it does not prevent the rest of the page from loading while the content of the iframe is loaded.

At AppNexus we’ve been developing some improved ad delivery mechanisms which leverage the advantages of iframes, in particular we’ve been leveraging the dynamic creation of iframes to serve ad content after some user interaction is applied. However, this has been a bit of an adventure as idiosyncrasies in how browsers handle the population of content in iframes and the rendering of their  documents.

Let me illustrate.

Here’s how we would use JavaScript to create a new iframe, give it some properties, set its initial source, and add it to the existing document.

var newIframe = document.createElement('iframe');
newIframe.width = '200';newIframe.height = '200';
newIframe.src = 'about:blank'; 
document.body.appendChild(newIframe);

I’ve set the src attribute to ‘about:blank’. This is generally a good practice because IE can behave strangely when an iframe is appended to the document without a source. Setting the src to about:blank makes this a “friendly” iframe which means that javascript code running inside the iframe can interact with the DOM and javascript defined in its parent window and vice versa. In other words, there are no restrictions on the communication and code execution between the iframe window and the parent window.

There are several different ways we can add content to our new iframe:

  • Change the src attribute to an external document URL
  • Use the DOM’s open(), write(), close() API to inject content
  • Use the javascript: URI scheme.

Here are examples of each approach.

I can set the src attribute to an external file:

newIframe.src = 'myIframeContent.html';

If this was my intent all along, then there’s no need to start with the ‘about:blank’ src. I can set this as the src directly.

This is not convenient if we don’t have access to the site’s initial domain, and we want to maintain the “friendly” nature of the iframe. In such a case we can use the DOM API to open the iframe’s document and dynamically write content into it.

var myContent = '<!DOCTYPE html>'
    + '<html><head><title>My dynamic document</head>'
    + '<body><p>Hello world</p></body></html>';

newIframe.contentWindow.document.open('text/html', 'replace');
newIframe.contentWindow.document.write(myContent);
newIframe.contentWindow.document.close();

First, I’d like to call out that the contentWindow isn’t created until we’ve added the iframe to the parent window’s DOM (which we did in the first code block above).

This approach is adequate to dynamically inject content into an iframe in most cases. However, if the content contains resources to external <script> resources you can run into problems in IE.

Look at this example in Chrome, and you will see an iframe populated with content using the approach above, and it includes a reference to an external script which provides content for the iframe.

However, if you look at the same page in IE, you will see a JavaScript error and no content is displayed in the iframe.

Here’s the code for the iframe:

var iframe = document.createElement('iframe');
var ctnr = document.getElementById('ctnr');
var content = '<!DOCTYPE html>'
 + '<head><title>Dynamic iframe</title>'
 + '<body><div id="innerCtnr"></div>'
 + '<script type="text/javascript" src="external.js"><\/script>'
 + '<script type="text/javascript">'
 + 'document.getElementById("innerCtnr").innerHTML = externalVar;'
 + '<\/script>' + '</body></html>';

ctnr.appendChild(iframe);

iframe.contentWindow.document.open('text/html', 'replace');
iframe.contentWindow.document.write(content);
iframe.contentWindow.document.close();

In external.js there is a variable defined which is referenced by the code which is being added in our document.write call. external.js is loaded asynchronous to the parsing of document.write(content), therefore at the time that we invoke this:

document.getElementById("innerCtnr").innerHTML = externalVar;

externalVar has not yet been defined and causes a ReferenceError.

To workaround this problem in IE we can make use of the javascript: URI scheme which makes bookmarklets and scriplets possible in all browsers. Instead of using document.open/write/close we use the following approach:

iframe.contentWindow.contents = content;
iframe.src = 'javascript:window["contents"]';

First, we assign the dynamic content to a variable on the iframe’s window object. Then we invoke it via the javascript: scheme. This not only renders the HTML properly, but loads and executes the scripts in the desired order.

Here’s an example using the javascript URI scheme.

Summary

Dynamic iframes are resourceful ways to add new content into a web page, but care and attention has to be paid as to how those iframes are injected with content to avoid errors caused by browser differences in loading and executing scripts added to those iframes.

About these ads

29 responses to “Inject Content into a new IFrame

  1. Wow, this is amazing. I was really dreading replicating jQuery.html() for this. Are there any limitations and/or browser compatibilities we should be aware of? What about SWF embeds?

  2. the links in your page are not working (external.js, and from “Look at this example in Chrome”). Could you please upload the files again?

  3. I would love to see the working examples as well. If you could make the links work, it would be appreciated!

  4. Thanks for this Post, I was looking for a way to make it works on IE7, I was using AJAX from a call to an external domain script, but it does not work on IE7, so I will change and make it work using iframe this way :)

  5. Any chance to get links to the real files? It’s all pointing to 404’s :(

  6. Still getting 404’s on the example links. Great article!

  7. Pingback: javascript,iframe,inject,URI scheme

  8. Pingback: JavaScript MVC Frameworks | Spare Cycles

  9. for line iframe.src = ‘javascript:window["contents"]‘ . does ‘javascript:window’ always refer to current iframe window Scope or GLobal window in IE . i mean what if same “contents” attribute or var is present at Global scope ???

  10. Hi, I wanted to see the examples too, but I had to figure it out them.
    Here you have them in case that you need them:
    ***external.js:
    var externalVar=”Hello”

    ***example.html (Look at this “example”)

    Hola

    var iframe = document.createElement(‘iframe’);
    var ctnr = document.getElementById(‘ctnr’);
    var content = ”
    + ‘Dynamic iframe’
    + ”
    + ”
    + ”
    + ‘document.getElementById(“innerCtnr”).innerHTML = externalVar;’
    + ” + ”;

    ctnr.appendChild(iframe);

    iframe.contentWindow.document.open(‘text/html’, ‘replace’);
    iframe.contentWindow.document.write(content);
    iframe.contentWindow.document.close();

    ***For the URI example, just change the 3 lines above at the end of the for these two:

    iframe.contentWindow.contents = content;
    iframe.src = ‘javascript:window["contents"]‘;

    • Jajaja, problems with the HTML page:

      
      ***external.js:
      var externalVar="Hello"
      
      ***example.html (Look at this "example")
      
      
      Hola
      
      
      var iframe = document.createElement('iframe');
      var ctnr = document.getElementById('ctnr');
      var content = ''
       + 'Dynamic iframe'
       + ''
       + ''
       + ''
       + 'document.getElementById("innerCtnr").innerHTML = externalVar;'
       + '' + '';
      
      ctnr.appendChild(iframe);
      
      iframe.contentWindow.document.open('text/html', 'replace');
      iframe.contentWindow.document.write(content);
      iframe.contentWindow.document.close();
      
      
      
      
      
      ***For the URI example, just change the 3 lines above at the end of the  for these two:
      
      iframe.contentWindow.contents = content;
      iframe.src = 'javascript:window["contents"]';
      
      
  11. OK, the things that are not showing correctly in the html page that I pasted here are:
    1. the value of the content var. Just copy it from the instructions
    2. The initial HTML, just add a html, and body tag surrounding all the code and add a < script type=”text/javascript” src=”external.js”> </script> to the java script section.

  12. Writing the college admission essay means to present your personal statement.
    The next articles in this series will interrupt the college tour for a few reflections on
    what makes for high quality in a university. Every student’s needs differ, but wherever you choose to study should be free of distraction, quiet, and clean.

  13. Wow this is amazing. We do a lot of ads and we use Non-Friendly Iframes with Post Message API for cross domain communication b/w publisher and our ad frames. But the “javascript URI” solutions makes it soo much easier. Thank you

  14. My developer is trying to convince me to move to .net from
    PHP. I have always disliked the idea because of the costs.
    But he’s tryiong none the less. I’ve been using WordPress on a number of websites
    for about a year and am concerned about switching to another platform.
    I have heard great things about blogengine.
    net. Is there a way I can import all my wordpress content into it?
    Any kind of help would be greatly appreciated!

  15. Thank you :)

  16. Hey there fantastic website! Does running
    a blog like this require a lot of work? I have no knowledge of coding however I had been hoping
    to start my own blog in the near future. Anyways, should you have any recommendations
    or techniques for new blog owners please share. I know this
    is off topic but I simply needed to ask. Many thanks!

  17. Nice post. I was checking continuously this blog
    and I’m impressed! Very helpful information specially the final phase :) I maintain such info much.
    I was seeking this particular information for a long time.
    Thank you and best of luck.

  18. Amazing, thanks for sharing!
    However I have an issue.
    If ‘content’ includes jQuery, using the ‘javascript:’ protocol document.ready does not fire at all – any suggestions?

    Cheers

  19. For the reason that the admin of this website is working, no hesitation very quickly it will be well-known, due to its quality contents.

  20. Have you ever considered creating an ebook or guest authoring on other blogs?
    I have a blog based on the same ideas you discuss and would love to have you share
    some stories/information. I know my subscribers would appreciate your work.
    If you are even remotely interested, feel free to shoot me an
    email.

  21. Hi,

    First thank you for the solution. However, I found an issue when working with special character (Ruassian alphabet for example). Characters do not translate properly in IE.

    For example, if you try something like:

    iframe.contentWindow.contents = ‘Некоторые данные в настоящий момент недоступны. Прино';
    iframe.src = ‘javascript:window["contents"]‘;

    content of the iframe then look something like:

    5:>B>@K5 40==K5 2 =0AB>OI89 ABC?=K. @8=>

    Do you have any idea how we could fix this bug?

    Best Regards,
    Julien

  22. For most recent news you have to pay a quick visit world-wide-web and on web I found this web page as a best
    site for newest updates.

  23. Nice article btw there is a tiny error in the example HTML for the inserted text, ie, no closing tag …

  24. Thanks very much for this post; it was exactly what I was looking for.

  25. Pingback: Sandbox local HTML/CSS code snippets inside an iframe (for style guides/pattern libraries) - Author and responsive web developer Ben Frain

  26. jyuumoutora@gmail.com

    Thank you ! It work !

  27. Keith Chadwick

    You just saved my ass on a nasty pos preview of some brutal css in a UI. I owe you a pint sir!!!

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