Why does appending a – Pointy Oct 19 '09 at 21:07

  • This is by-design in order to prevent cross site scripting. If you could inject script into another site in the fashion you're attempting you could inject script from any iframe container to any website without issue. – Keith Adler Oct 19 '09 at 21:14
  • Well, I'd think that the "same domain" rules would prevent the addition of any content at all to the document in the iframe. If the document is from the same domain, however, the rules don't apply. – Pointy Oct 19 '09 at 21:20
  • @Pointy - Thanks very much for your input. Your idea sounds like it could work - I gave it a try but couldn't make it work (though that doesn't mean it's not a valid solution). I ended up going with the code in my answer below, which is a more elegant solution for my purposes. – Bungle Oct 19 '09 at 22:11
  • @Nissan Fan - Thanks for the feedback. However, Pointy is correct - since this – Bungle Oct 19 '09 at 22:13
  • 3 Answers3

    74

    Had the same problem, took me hours to find the solution. You just need to create the script's object using the iframe's document.

    var myIframe = document.getElementById("myIframeId");
    var script = myIframe.contentWindow.document.createElement("script");
    script.type = "text/javascript";
    script.src = src;
    myIframe.contentWindow.document.body.appendChild(script);
    

    Works like a charm!

    Oleg Grishko
    • 4,132
    • 2
    • 38
    • 52
    • 1
      Awesome... was working on same thing from hours... got it fixed now – Aman Virk Mar 09 '12 at 05:57
    • 2
      @user2284570 Is there a way to do this cross-domain? – Stan James Sep 19 '15 at 00:36
    • @StanJames : Dunno, but that would typically lead to cross AJAX without ᴄᴏʀꜱ. – user2284570 Sep 19 '15 at 20:31
    • @StanJames cross domain iframes are totally different ball game. Even if there was a solution, the browsers will path them pretty soon. It's a security feature to prevent bad guys hack your bank passwords and so on. – Gogol Mar 23 '17 at 08:37
    • btw, I suggest using this for the content window, for the sake of browser compatibility: `var doc = iframe.contentDocument ? iframe.contentDocument : (iframe.contentWindow ? iframe.contentWindow.document : iframe.document);` – Gogol Mar 23 '17 at 08:41
    16

    I didn't find an answer to my original question, but I did find another approach that works even better (at least for my purposes).

    This doesn't use jQuery on the parent page (which is actually a good thing, as I'd prefer not to load it there), but it does load jQuery in the <iframe> in an apparently completely valid and usable way. All I'm doing is writing over the <iframe>'s document object with a new one created from scratch. This allows me to simply include a <script> element in a string which I then write to the <iframe>'s document object.

    The code:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>frame</title>
      </head>
      <body>
    
        <div id="test"></div>
    
        <script type="text/javascript">
          // create a new <iframe> element
          var iframe = document.createElement('iframe');
    
          // append the new element to the <div id="bucket"></div>
          var bucket = document.getElementById('test');
          bucket.appendChild(iframe);
    
          // create a string to use as a new document object
          var val = '<scr' + 'ipt type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></scr' + 'ipt>';
          val += '<scr' + 'ipt type="text/javascript"> $(function() { $("body").append("<h1>It works!</h1>"); }); </scr' + 'ipt>';
    
          // get a handle on the <iframe>d document (in a cross-browser way)
          var doc = iframe.contentWindow || iframe.contentDocument;
          if (doc.document) {
            doc = doc.document;
          }
    
          // open, write content to, and close the document
          doc.open();
          doc.write(val);
          doc.close();
        </script>
    
      </body>
    </html>
    

    I hope this helps someone down the road!

    Bungle
    • 19,392
    • 24
    • 79
    • 106
    0

    The answer to the original question is simple - the execution of the script is done by jquery, and since jquery is loaded in the top frame, this is where the script runs too, no matter where you are appending it. A smarter implementation of jquery can no doubt be made to use the correct window object, but for now things are how they are.

    As to the workarounds, you already have two good answers (even if one is your own). What I might add is that you can use one of those workarounds to include jquery.js in the iframe, and then get that jquery object instead of the top one to insert your additional markup... but that may very well be overkill too.