iframe contentWindow is undefined when use window.frames[name] to access - javascript

If use following way to get the contentWindow, the value is undefined
<html>
<head>
<title>iframe test</title>
</head>
<body>
<iframe id="frame1" src="frame1.html" name="frame1"></iframe>
<script>
document.body.onload = function() {
console.info("index loaded");
var frame1 = window.frames["frame1"];
console.info(frame1.contentWindow);
}
</script>
</body>
</html>
If use the other way like following, it works fine:
var frame1 = document.getElementById("frame1");
console.info(frame1.contentWindow);
I tested on FF 29.0.1, chrome 34, IE11, they all work the same way.
So I have two questions:
why the first way can't get contentWindow value
iframe.contentWindow is compatible in all browser?

window.frames["frame1"];
is the contentWindow, it gets a named window, and in your case it's the same thing as
document.getElementById("frame1").contentWindow
FIDDLE

Related

Why can't I traverse this element using iframe object and jQuery?

I'm trying to access a particular element (maybe more similar to this) using iframe object and jQuery but it isn't working.
The iframeWindow object is not null but the next statement doesn't seem working. I saw something like this on this answer but it doesn't work. Am I doing something wrong?
Here's my code:
RADIO.PHP
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript" src="jquery.js"></script>
<script>
$(document).ready(function(){
setTimeout(function(){
var iframe= document.getElementById("iframe");
var iframeWindow = iframe.contentWindow;
var text=iframeWindow.$("div:nth-child(3) .c2").html();
console.log(text);
//DOESN'T PRINT "INNER MOST"
}, 1000);
});
</script>
</head>
<body>
<div class="c1">
<iframe id="iframe" src="api.php" height="200" width="300">
</iframe>
</div>
</body>
</html>
API.PHP
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<script type="text/javascript" src="jquery.js"></script>
<body id="abody">
Hey
<div class="c1"></div>
<div class="c1">
<p class="c2"></p>
</div>
<div class="c1">
<p class="c2">
INNER MOST
</p>
</div>
</body>
</html>
EDIT: I've corrected syntax mistakes.
You should use iframe.contentWindow.document instead of iframe.contentWindow in combination with find() and text() and it should work. Try this:
$(document).ready(function() {
setTimeout(function() {
var iframe = document.getElementById("iframe");
var iframeWindow = iframe.contentWindow.document;
var text = $(iframeWindow).find(".c1:nth-child(3) .c2").text();
console.log(text);
//PRINTS "INNER MOST"
}, 1000);
});
As per MDN documentation says:
The contentWindow property returns the Window object of an iframe element. You can use this Window object to access the iframe's document and its internal DOM. This attribute is read-only, but its properties can be manipulated like the global Window object.
You can read more about iframe elements and how they work here.
To specify a scope for a selector in jQuery, pass the scope as a second argument to the jQuery selector.
Replace:
inframeWindow.$("div:nth-child(3) p .c2")
with
$("div:nth-child(3) p .c2", inframeWindow)
(Also, there is no $ member function on DOM or jQuery objects.)
That is something obvious to see the typo which i and all other missed, instead of inframeWindow that should have to be iframeWindow.
Instead try with jquery selector:
var text=$(iframeWindow).find("div:nth-child(3) .c2").html();
You are attaching a jquery method to a DOM object. which can't be done in that way. You have to make it a jQuery object to assign a jQuery method.
Try this way hope it will help
Updated Answer
var $iframe= $("#iframe");
var $iframeWindow = $iframe.contents();
var text=$iframeWindow.find("div").eq(2).find('p .c2').html();
console.log(text);

First opportunity for document.body.appendChild

I am looking for the first opportunity to call document.body.appendChild to attach an element. I am currently using onload of body but as I understand it this waits until images and subframes load before triggering.
I require only that the solution work in IE (this is for an IE specific demo), but believe in the importance of giving cross-browser answers for other people to reference, so points if you give both.
Below is an illustration of what I am already doing.
<html>
<head>
<title>Insertion</title>
<script type="text/javascript">
function insertStuff() {
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
}
</script>
</head>
<body onload="insertStuff()">
</body>
</html>
<html>
<head>
<title>Insertion</title>
</head>
<body>
<script type="text/javascript">
function insertStuff() {
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
}
insertStuff()
</script>
<!-- Here goes all the other elements -->
</body>
</html>
This would be cross browser and work for IE6 and above for sure. Not sure about anything below that

How to access a method of parent window of an Iframe [Chrome browser ]

I tried many times and many ways to call the method from inside the iframe while not yet successful to do so. please see below,
main.html : consisting the two iframe
iframe-1 linked with a index.html from where i want to call a method of main.html or want to change the src of second iframe.
main.html
<html>
<head> </head>
<body>
<iframe id="iframe-1" src="index.html"></iframe>
<iframe id="iframe-2" ></iframe>
</body>
</html>
index.html
<html> <head>
<script type="text/javascript">
$(document).ready(function(){
// How to access the method of main.html and change the iframe src
});
</script>
</head> <body>
......
</body> </html>
Note : tried parent.methodName(), window.parent.methodName() not working
#EDIT : success on IE & MOZILLA but getting error on Chrome ( Cannot call method 'getElementById' of undefined )
You should try with
document.getElementById("iframe-1").contentWindow.func();
or
var $f = $("#myIFrame");
var fd = $f[0].document || $f[0].contentWindow.document; // document of iframe
fd.MyFunction(); // run function
Docs
I am keeping this short.
As you are looking forward for the iframes/frames on same document[window sharing]. To access a variable defined in one document inside another document.You have to use document.importNode(original Node as in other document,boolean) method as per DOM 2.
Do something like this for javacript code ...
iframe=document.getElementsTagName("iframe")[0];
documentI(original variable/node present here)-
OriginalNode=iframe.contentWindow.document.getElementsByTagName(//Tag name of Node//)
documentII(node to be cloned here)- iframe.contentWindow.document.importNode(OriginalNode,True)
Node can be created of any method,property or object in any iframe by simple DOM methods.
This would work
index.html
<html>
<head>
<script type="text/javascript">
function run() {
window.parent.document.getElementById("iframe-2").src = "/test.html";
}
</script>
</head>
<body onload="run();">
</body>
</html>
How about this?
Or create a method inside main.html and access it using:
window.parent.methodname();
Ron.
ps. window.parent.methodname(); works perfectly for me when I have a method in main.html
main.html
<html>
<head> </head>
<script>
function foo() {
alert(1);
}
</script>
<body>
<iframe id="iframe-1" src="index.html"></iframe>
<iframe id="iframe-2" ></iframe>
</body>
</html>

Nested iframes, AKA Iframe Inception

Using jQuery I am trying to access div id="element".
<body>
<iframe id="uploads">
<iframe>
<div id="element">...</div>
</iframe>
</iframe>
</body>
All iframes are on the same domain with no www / non-www issues.
I have successfully selected elements within the first iframe but not the second nested iframe.
I have tried a few things, this is the most recent (and a pretty desperate attempt).
var iframe = jQuery('#upload').contents();
var iframeInner = jQuery(iframe).find('iframe').contents();
var iframeContent = jQuery(iframeInner).contents().find('#element');
// iframeContent is null
Edit:
To rule out a timing issue I used a click event and waited a while.
jQuery().click(function(){
var iframe = jQuery('#upload').contents().find('iframe');
console.log(iframe.find('#element')); // [] null
});
Any ideas?
Thanks.
Update:
I can select the second iframe like so...
var iframe = jQuery('#upload').contents().find('iframe');
The problem now seems to be that the src is empty as the iframe is generated with javascript.
So the iframe is selected but the content length is 0.
Thing is, the code you provided won't work because the <iframe> element has to have a "src" property, like:
<iframe id="uploads" src="http://domain/page.html"></iframe>
It's ok to use .contents() to get the content:
$('#uploads).contents() will give you access to the second iframe, but if that iframe is "INSIDE" the http://domain/page.html document the #uploads iframe loaded.
To test I'm right about this, I created 3 html files named main.html, iframe.html and noframe.html and then selected the div#element just fine with:
$('#uploads').contents().find('iframe').contents().find('#element');
There WILL be a delay in which the element will not be available since you need to wait for the iframe to load the resource. Also, all iframes have to be on the same domain.
Hope this helps ...
Here goes the html for the 3 files I used (replace the "src" attributes with your domain and url):
main.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>main.html example</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(function () {
console.log( $('#uploads').contents().find('iframe').contents().find('#element') ); // nothing at first
setTimeout( function () {
console.log( $('#uploads').contents().find('iframe').contents().find('#element') ); // wait and you'll have it
}, 2000 );
});
</script>
</head>
<body>
<iframe id="uploads" src="http://192.168.1.70/test/iframe.html"></iframe>
</body>
iframe.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>iframe.html example</title>
</head>
<body>
<iframe src="http://192.168.1.70/test/noframe.html"></iframe>
</body>
noframe.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>noframe.html example</title>
</head>
<body>
<div id="element">some content</div>
</body>
var iframeInner = jQuery(iframe).find('iframe').contents();
var iframeContent = jQuery(iframeInner).contents().find('#element');
iframeInner contains elements from
<div id="element">other markup goes here</div>
and iframeContent will find for elements which are inside of
<div id="element">other markup goes here</div>
(find doesn't search on current element) that's why it is returning null.
Hey I got something that seems to be doing what you want a do. It involves some dirty copying but works. You can find the working code here
So here is the main html file :
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
Iframe = $('#frame1');
Iframe.on('load', function(){
IframeInner = Iframe.contents().find('iframe');
IframeInnerClone = IframeInner.clone();
IframeInnerClone.insertAfter($('#insertIframeAfter')).css({display:'none'});
IframeInnerClone.on('load', function(){
IframeContents = IframeInner.contents();
YourNestedEl = IframeContents.find('div');
$('<div>Yeepi! I can even insert stuff!</div>').insertAfter(YourNestedEl)
});
});
});
</script>
</head>
<body>
<div id="insertIframeAfter">Hello!!!!</div>
<iframe id="frame1" src="Test_Iframe.html">
</iframe>
</body>
</html>
As you can see, once the first Iframe is loaded, I get the second one and clone it. I then reinsert it in the dom, so I can get access to the onload event. Once this one is loaded, I retrieve the content from non-cloned one (must have loaded as well, since they use the same src). You can then do wathever you want with the content.
Here is the Test_Iframe.html file :
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>Test_Iframe</div>
<iframe src="Test_Iframe2.html">
</iframe>
</body>
</html>
and the Test_Iframe2.html file :
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>I am the second nested iframe</div>
</body>
</html>
You probably have a timing issue. Your document.ready commend is probably firing before the the second iFrame is loaded. You dont have enough info to help much further- but let us know if that seems like the possible issue.
You should use live method for elements which are rendered later, like colorbox, hidden fields or iframe
$(".inverter-value").live("change",function() {
elem = this
$.ajax({
url: '/main/invertor_attribute/',
type: 'POST',
aysnc: false,
data: {id: $(this).val() },
success: function(data){
// code
},
dataType: 'html'
});
});
I think the best way to reach your div:
var your_element=$('iframe#uploads').children('iframe').children('div#element');
It should work well.
If browser supports iframe, then DOM inside iframe come from src attribute of respective tag. Contents that are inside iframe tag are used as a fall back mechanism where browser does not supports iframe tag.
Ref: http://www.w3schools.com/tags/tag_iframe.asp
I guess your problem is that jQuery is not loaded in your iframes.
The safest approach is to rely on pure DOM-based methods to parse your content.
Or else, start with jQuery, and then once inside your iframes, test once if typeof window.jQuery == 'undefined', if it's true, jQuery is not enabled inside it and fallback on DOM-based method.

Write elements into a child iframe using Javascript or jQuery

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)
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();
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>");
There are two reliable methods to access the document element inside an iframe:
1. The window.frames property:
var iframeDocument = window.frames['iframeName'].document; // or // var iframeDocument = window.frames[iframeIndex].document;
Demo
2. The contentDocument property:
var iframeDocument = document.getElementById('iframeID').contentDocument; // or // var iframeDocument = document.getElementById('iframeID').contentWindow.document;
Demo
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:
Pass some kind of object to the containing page that can be used as a bridge
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...
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?

Categories

Resources