Access Iframe Elements in JavaScript

Get element from within an iFrame

var iframe = document.getElementById('iframeId');
var innerDoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;

You could more simply write:

var iframe = document.getElementById('iframeId');
var innerDoc = iframe.contentDocument || iframe.contentWindow.document;

and the first valid inner doc will be returned.

Once you get the inner doc, you can just access its internals the same way as you would access any element on your current page. (innerDoc.getElementById...etc.)

IMPORTANT: Make sure that the iframe is on the same domain, otherwise you can't get access to its internals. That would be cross-site scripting. Reference:

  • MDN: <iframe> Scripting
  • MDN: Same-Origin Policy: Cross-Origin Script API Access

Access iframe elements in JavaScript

If your iframe is in the same domain as your parent page you can access the elements using window.frames collection.

// replace myIFrame with your iFrame id
// replace myIFrameElemId with your iFrame's element id
// you can work on window.frames['myIFrame'].document like you are working on
// normal document object in JS
window.frames['myIFrame'].document.getElementById('myIFrameElemId')

If your iframe is not in the same domain the browser should prevent such access for security reasons.

Accessing element within iFrame

You have the var object for the YouTube player already so there's no need to navigate the DOM.

For example:

// Play the video
function onPlayerReady(event) {
player.playVideo();
console.log(player.getCurrentTime());

// Jump to 10 seconds
player.seekTo(10);

// Stop the video after 3 seconds
setTimeout(stopVideo, 3000);
}

function stopVideo() {
console.log(player.getCurrentTime());
player.stopVideo();
}

How can I access iframe elements with Javascript?

If you have the HTML

<form name="formname" .... id="form-first">
<iframe id="one" src="iframe2.html">
</iframe>
</form>

and JavaScript

function iframeRef( frameRef ) {
return frameRef.contentWindow
? frameRef.contentWindow.document
: frameRef.contentDocument
}

var inside = iframeRef( document.getElementById('one') )

inside is now a reference to the document, so you can do getElementsByTagName('textarea') and whatever you like, depending on what's inside the iframe src.

Control iframe content with javascript/html

Yes you can. Say your iframe's ID is 'myIFrame'

<iframe id="myIFrame" src="thispage.html"
width="100%" height="600"
frameBorder="2">
</iframe>

Then, add the following in your JavaScript:

// Get the iframe
const iFrame = document.getElementById('myIFrame');

// Let's say that you want to access a button with the ID `'myButton'`,
// you can access via the following code:
const buttonInIFrame = iFrame.contentWindow.document.getElementById('myButton');

// If you need to call a function in the iframe, you can call it as follows:
iFrame.contentWindow.yourFunction();

Hope it helps :)

How can I access the DOM elements within an iFrame

Chrome has default security restrictions that don't allow you to access other windows from the hard disk even though they are technically the same origin. There is a flag in Chrome that can relax that security restriction (command line argument on Windows is what I remember), though I wouldn't recommend running with that flag for more than a quick test. See this post or this article for info about the command line argument.

If you run the files off a web server (even if it's a local web server) instead of your hard drive, you won't have this issue.

Or, you could test in other browsers that aren't as restrictive.


Now that you've changed the question into something different, you have to wait for an iframe window to load before you can access the content in it and you can't use jQuery's .ready() on a different document (it doesn't work on another document).

$(document).ready(function() {
// get the iframe in my documnet
var iframe = document.getElementById("testFrame");
// get the window associated with that iframe
var iWindow = iframe.contentWindow;

// wait for the window to load before accessing the content
iWindow.addEventListener("load", function() {
// get the document from the window
var doc = iframe.contentDocument || iframe.contentWindow.document;

// find the target in the iframe content
var target = doc.getElementById("target");
target.innerHTML = "Found It!";
});
});

Test page here.


EDIT: Upon further research, I found that jQuery will do some of this work for you like this and the jQuery solution appears to work in all the major browsers:

$(document).ready(function() {
$("#testFrame").load(function() {
var doc = this.contentDocument || this.contentWindow.document;
var target = doc.getElementById("target");
target.innerHTML = "Found It!";
});
});

Test page here.

In looking at the jQuery implementation for this, all it is really doing is setting up a load event listener on the iFrame itself.


If you want to know the nitty gritty details that went into debugging/solving the first method above:

In my trying to solve this issue, I discovered some pretty bizarre things (in Chrome) with iFrames. When you first look in the window of the iframe, there is a document and it says that its readyState === "complete" such that you think it's done loading, but it's lying. The actual document and actual <body> tag from the document that is being loaded via URL into the iframe is NOT actually there yet. I proved this by putting a custom attribute on the <body data-test="hello"> and checking for that custom attribute. Lo and behold. Even though document.readyState === "complete", that custom attribute is not there on the <body> tag. So, I conclude (at least in Chrome) that the iFrame initially has a dummy and empty document and body in it that are not the actual ones that will be in place once the URL is loaded into the iFrame. This makes this whole process of detecting when it's ready to be quite confusing (it cost me hours figuring this out). In fact, if I set an interval timer and poll iWindow.document.body.getAttribute("data-test"), I will see it show as undefined repeatedly and then finally it will show up with the correct value and all of this with document.readyState === "complete" which means it's completely lying.

I think what's going on is that the iFrame starts out with a dummy and empty document and body which is then replaced AFTER the content starts loading. On the other hand, the iFrame window is the real window. So, the only ways I've found to actually wait for the content to be loaded are to monitor the load event on the iFrame window as that doesn't seem to lie. If you knew there was some specific content you were waiting for, you could also poll until that content was available. But, even then you have to be careful because you cannot fetch the iframe.contentWindow.document too soon because it will be the wrong document if you fetch it too soon. The whole thing is pretty broken. I can't find any way to use DOMContentLoaded from outside the iFrame document itself because you have no way of knowing then the actual document object is in place to you can attach the event handler to it. So ... I settled for the load event on the iFrame window which does seem to work.


If you actually control the code in the iFrame, then you can trigger the event more easily from the iFrame itself, either by using jQuery with $(document).ready() in the iFrame code with it's own version of jQuery or by calling a function in the parent window from a script located after your target element (thus ensuring the target element is loaded and ready).


Further Edit

After a bunch more research and testing, here's a function that will tell you when an iFrame hits the DOMContentLoaded event rather than waiting for the load event (which can take longer with images and style sheets).

// This function ONLY works for iFrames of the same origin as their parent
function iFrameReady(iFrame, fn) {
var timer;
var fired = false;

function ready() {
if (!fired) {
fired = true;
clearTimeout(timer);
fn.call(this);
}
}

function readyState() {
if (this.readyState === "complete") {
ready.call(this);
}
}

// cross platform event handler for compatibility with older IE versions
function addEvent(elem, event, fn) {
if (elem.addEventListener) {
return elem.addEventListener(event, fn);
} else {
return elem.attachEvent("on" + event, function () {
return fn.call(elem, window.event);
});
}
}

// use iFrame load as a backup - though the other events should occur first
addEvent(iFrame, "load", function () {
ready.call(iFrame.contentDocument || iFrame.contentWindow.document);
});

function checkLoaded() {
var doc = iFrame.contentDocument || iFrame.contentWindow.document;
// We can tell if there is a dummy document installed because the dummy document
// will have an URL that starts with "about:". The real document will not have that URL
if (doc.URL.indexOf("about:") !== 0) {
if (doc.readyState === "complete") {
ready.call(doc);
} else {
// set event listener for DOMContentLoaded on the new document
addEvent(doc, "DOMContentLoaded", ready);
addEvent(doc, "readystatechange", readyState);
}
} else {
// still same old original document, so keep looking for content or new document
timer = setTimeout(checkLoaded, 1);
}
}
checkLoaded();
}

This is simply called like this:

// call this when you know the iFrame has been loaded
// in jQuery, you would put this in a $(document).ready()
iFrameReady(document.getElementById("testFrame"), function() {
var target = this.getElementById("target");
target.innerHTML = "Found It!";
});


Related Topics



Leave a reply



Submit