55

I have something like this:

<!doctype html>
<html>
  <body>
     <iframe id="someFrame"></iframe>
  </body>
</html>

And I would like to use jQuery to write elements such that the full equivalent HTML would be like this:

<!doctype html>
<html>
  <body>
    <iframe id="someFrame">
      <!-- inside the iframe's content -->
      <!-- <html><body>  -->
      <div>A</div>
      <div>B</div>
      <div>C</div>
      <!-- </body></html> -->
    </iframe>
  </body>
</html>

Alternatively, any plain-old-Javascript would be fine.

Thanks.

Edit: After a little more research, it seems I am looking for an IE-equivalent of the contentDocument property of an iframe. "contentDocument" is a W3C standard which FF supports, but IE does not. (surprise surprise)

calvinf
  • 3,754
  • 3
  • 28
  • 41
Jeff Meatball Yang
  • 37,839
  • 27
  • 91
  • 125

5 Answers5

97

You can do both, you just have to target differently:

var ifrm = document.getElementById('myIframe');
ifrm = ifrm.contentWindow || ifrm.contentDocument.document || ifrm.contentDocument;
ifrm.document.open();
ifrm.document.write('Hello World!');
ifrm.document.close();
Josh Stodola
  • 81,538
  • 47
  • 180
  • 227
Mike Robinson
  • 24,971
  • 8
  • 61
  • 83
  • 2
    aha - contentWindow. I actually found that open and close are necessary to start using jquery... – Jeff Meatball Yang Jun 15 '09 at 20:47
  • this method no longer works. I get js error that says Unsafe JavaScript attempt to access frame with URL "URL1" from frame with URL "URL2". Domains, protocols and ports must match. The bridge approach given bellow does work fine. – kay am see Aug 25 '12 at 22:21
  • 1
    I know this an old thread but in what case would you ever have `ifrm.contentDocument.document.document`? – ars265 Sep 18 '13 at 15:35
  • Why is it not possible to write directly into body of an iframe but only with this hack? – Kiechlus Jan 24 '18 at 11:17
  • without close() statement all following JS are not executed, so it make sense to use try finally block. thanks. this answer helped me to figure out what is wrong with my page – user2932688 Mar 23 '18 at 13:52
  • This doesn't seem to work in Firefox – chovy Nov 21 '21 at 19:39
36

After some research, and a corroborating answer from Mike, I've found this is a solution:

  var d = $("#someFrame")[0].contentWindow.document; // contentWindow works in IE7 and FF
  d.open(); d.close(); // must open and close document object to start using it!

  // now start doing normal jQuery:
  $("body", d).append("<div>A</div><div>B</div><div>C</div>");
Jeff Meatball Yang
  • 37,839
  • 27
  • 91
  • 125
12

HTMLIFrameElement: srcdoc property

The srcdoc property of the HTMLIFrameElement specifies the content of the page.

document.querySelector("button").addEventListener("click", function() {
  document.querySelector("iframe").srcdoc = "Hello, world!";
});
<iframe></iframe>
<button>Write</button>
Mori
  • 8,137
  • 19
  • 63
  • 91
7

I am going out on a limb here and suggest that the answers proposed so far are not possible.

If this iframe actually has a src="somepage.html" (which you ought to have indicated, and if not, what is the point of using iframe?), then I do not think Jquery can directly manipulate html across frames in all browsers. Based on my experience with this kind of thing, the containing page cannot directly call functions from or make any sort of Javascript contact with the iframe page.

Your "somepage.html" (the page that loads in the iframe) needs to do two things:

  1. Pass some kind of object to the containing page that can be used as a bridge
  2. Have a function to set the HTML as you desired

So for example, somepage.html might look like this:

<!doctype html>
<html>
<head>
<script src="jquery.js">
</script>
<script language=JavaScript>
<!--//
    var bridge={
        setHtml:function(htm) {
            document.body.innerHTML=htm;
        }
    }

    $(function() { parent.setBridge(bridge); });

//--></script>
</head>
<body></body>
</html>

and the containing page might look like this:

<!doctype html>
<html>
<head>
<script src="jquery.js">
</script>
<script language=JavaScript>
<!--//
var bridge;
var setBridge=function(br) {
    bridge=br;
    bridge.setHtml("<div>A</div><div>B</div><div>C</div>");
    }
//-->
</script>
</head>
<body><iframe src="somepage.html"></iframe></body>
</html>

This may appear a bit convoluted but it can be adapted in a number of directions and should work in at least IE, FF, Chrome, and probably Safari and Opera...

calvinf
  • 3,754
  • 3
  • 28
  • 41
jwl
  • 10,268
  • 14
  • 53
  • 91
  • Thanks for your answer - but I want to use this iframe to compose HTML like a rich text editor. I don't set the src attribute since it will be cleared out and re-composed from the "top" window. Also - I think it must be possible to reach into the child's DOM - see my edit in the OP. – Jeff Meatball Yang Jun 15 '09 at 20:22
  • Is there any reason you need to use an iframe and not a div? seems like the div would be easier and less likely to break across browsers. – Jeremy Wall Jun 15 '09 at 21:44
  • 1
    Turns out, there is a reason. You need to place external javascript and don't want it to damage your page. But you also need the referer to match your top-level domain. This is the most common method of placing ads on a page: + document.write(' – KateYoak Dec 10 '15 at 19:52
1

I have found this to be cross-browser compatible... a little crossing of previous answers and a bit of trial & error of my own. :)

I'm using this for a download of a report, or, if an error (message) occurs, it's displayed in the iFrame. Most of the users will probably have the iFrame hidden, I'm using it multi-functional.

The thing is I have to clear the contents of the iFrame every time I click the report download button - the user can change parameters and it happens there are no results which then is displayed in the iFrame as a message. If there are results, the iFrame remains empty - because the code below has cleared it and the window.open(...) method generates a Content-Disposition: attachment;filename=... document.

var $frm = $("#reportIFrame");
var $doc = $frm[0].contentWindow ? $frm[0].contentWindow.document : $frm[0].contentDocument;
var $body = $($doc.body);
$body.html(''); // clear iFrame contents <- I'm using this...
$body.append('<i>Writing into the iFrame...</i>'); // use this to write something into the iFrame
window.open(Module.PATH + 'php/getReport.php' + Report.queryData, 'reportIFrame');

I do not have a browser that supports contentDocument but I've coded it this way so I'm leaving it. Maybe someone has older browsers and can post compatibility confirmation/issues?

damijank
  • 91
  • 1
  • 4