How to expose IFrame's DOM using jQuery?
I have a prototype representing a particual IFrame. That prototype have a function called GoToUrl(...) that opens the given url within the IFrame.
My question is: How do I create an "InternalDOM" property and make this property refer to the "window" object (the root DOM object) of the IFrame inside? In such way that: If my IFrame exposes a page which has an object X in it's "window" object I could do:
MyFrameObject.GoToUrl(pageXurl);
MyFrameObject.InternalDOM.X
Any help would be appreciated.
PS: I would accept answers not necessarily related to jQuery but I would prefer a jQuery solution.
Solution 1:
To get the window
object for a frame you can use the window.frames
array:
var iframewindow= frames['iframe_name'];
This requires that you give the <iframe>
an old-school name
attribute instead-of-or-as-well-as the id
. Alternatively if you know the order of iframes on the page you can index them numerically:
var iframewindow= frames[0];
It's generally more flexible to get the iframe window from the iframe element in the DOM, but this requires some compatibility code to cope with IE:
var iframe= document.getElementById('iframe_id');
var iframewindow= iframe.contentWindow? iframe.contentWindow : iframe.contentDocument.defaultView;
jQuery defines the contents() method to grab the document
node, but it doesn't give you a cross-browser way to go from the document
to the window
, so you're still stuck with:
var iframe= $('#iframe_id')[0];
var iframewindow= iframe.contentWindow? iframe.contentWindow : iframe.contentDocument.defaultView;
which isn't really a big win.
(Note: be very careful using jQuery for cross-frame-scripting. Each frame needs its own copy of jQuery and methods from one frame's copy won't necessarily work on nodes from the other. Cross-frame-scripting is a topic fraught with traps.)
Solution 2:
To sum it up
Access iframe content from parent page
var iframe = $('iframe').contents(); // iframe.find('..') ...
Access parent page content from iframe
var parent = $(window.parent.document); // parent.find('..') ...
This applies only when the parent and the iframe pages are on same domain.
EDIT: On load child iframes example:
parent html
<iframe id="iframe1" src="iframe1.html"></iframe>
<iframe id="iframe2" src="iframe2.html"></iframe>
parent js
$(function () {
var iframe1 = null,
iframe2 = null;
// IE8/7
var frameInterval = window.setInterval(function () {
iframe1 = $('#iframe1').contents();
iframe2 = $('#iframe2').contents();
if ($('head', iframe1).length && $('head', iframe2).length) {
window.clearInterval(frameInterval);
}
}, 100);
// on iframe loaded
$('#iframe1').on('load', function (e) {
iframe1 = $('#iframe1').contents();
});
$('#iframe2').on('load', function (e) {
iframe2 = $('#iframe2').contents();
});
});
All major browsers including IE9 work with the on('load')
lines. Only IE8/7 need the interval block.
Solution 3:
UPDATE @RoyiNamir 's comment:
var frames = window.frames || window.document.frames;
for window in a iframe.
frames["myIframeId"].window
for document in a iframe
frames["myIframeId"].window.document
for body in a iframe
frames["myIframeId"].window.document.body
for body in a iframe with jquery
var iframeBody = $(frames["myIframeId"].window.document).contents().find("body");
IMPORTANT: you should always check that the document is with the status "complete" for work with this
if (frames["myIframeId"].window.document.readyState=="complete")
{
//ok
}
else
{
//perform a recursive call until it is complete
}