How can I access the contents of an iframe with JavaScript/jQuery? - javascript
I would like to manipulate the HTML inside an iframe using jQuery.
I thought I'd be able to do this by setting the context of the jQuery function to be the document of the iframe, something like:
$(function(){ //document ready
$('some selector', frames['nameOfMyIframe'].document).doStuff()
});
However this doesn't seem to work. A bit of inspection shows me that the variables in frames['nameOfMyIframe'] are undefined unless I wait a while for the iframe to load. However, when the iframe loads the variables are not accessible (I get permission denied-type errors).
Does anyone know of a work-around to this?
If the <iframe> is from the same domain, the elements are easily accessible as
$("#iFrame").contents().find("#someDiv").removeClass("hidden");
Reference
I think what you are doing is subject to the same origin policy. This should be the reason why you are getting permission denied type errors.
You could use .contents() method of jQuery.
The .contents() method can also be used to get the content document of an iframe, if the iframe is on the same domain as the main page.
$(document).ready(function(){
$('#frameID').load(function(){
$('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!');
});
});
If the iframe src is from another domain you can still do it. You need to read the external page into PHP and echo it from your domain. Like this:
iframe_page.php
<?php
$URL = "http://external.com";
$domain = file_get_contents($URL);
echo $domain;
?>
Then something like this:
display_page.html
<html>
<head>
<title>Test</title>
</head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
cleanit = setInterval ( "cleaning()", 500 );
});
function cleaning(){
if($('#frametest').contents().find('.selector').html() == "somthing"){
clearInterval(cleanit);
$('#selector').contents().find('.Link').html('ideate tech');
}
}
</script>
<body>
<iframe name="frametest" id="frametest" src="http://yourdomain.com/iframe_page.php" ></iframe>
</body>
</html>
The above is an example of how to edit an external page through an iframe without the access denied etc...
Use
iframe.contentWindow.document
instead of
iframe.contentDocument
I find this way cleaner:
var $iframe = $("#iframeID").contents();
$iframe.find('selector');
You need to attach an event to an iframe's onload handler, and execute the js in there, so that you make sure the iframe has finished loading before accessing it.
$().ready(function () {
$("#iframeID").ready(function () { //The function below executes once the iframe has finished loading
$('some selector', frames['nameOfMyIframe'].document).doStuff();
});
};
The above will solve the 'not-yet-loaded' problem, but as regards the permissions, if you are loading a page in the iframe that is from a different domain, you won't be able to access it due to security restrictions.
You can use window.postMessage to call a function between page and his iframe (cross domain or not).
Documentation
page.html
<!DOCTYPE html>
<html>
<head>
<title>Page with an iframe</title>
<meta charset="UTF-8" />
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
var Page = {
id:'page',
variable:'This is the page.'
};
$(window).on('message', function(e) {
var event = e.originalEvent;
if(window.console) {
console.log(event);
}
alert(event.origin + '\n' + event.data);
});
function iframeReady(iframe) {
if(iframe.contentWindow.postMessage) {
iframe.contentWindow.postMessage('Hello ' + Page.id, '*');
}
}
</script>
</head>
<body>
<h1>Page with an iframe</h1>
<iframe src="iframe.html" onload="iframeReady(this);"></iframe>
</body>
</html>
iframe.html
<!DOCTYPE html>
<html>
<head>
<title>iframe</title>
<meta charset="UTF-8" />
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
var Page = {
id:'iframe',
variable:'The iframe.'
};
$(window).on('message', function(e) {
var event = e.originalEvent;
if(window.console) {
console.log(event);
}
alert(event.origin + '\n' + event.data);
});
$(window).on('load', function() {
if(window.parent.postMessage) {
window.parent.postMessage('Hello ' + Page.id, '*');
}
});
</script>
</head>
<body>
<h1>iframe</h1>
<p>It's the iframe.</p>
</body>
</html>
I prefer to use other variant for accessing.
From parent you can have a access to variable in child iframe.
$ is a variable too and you can receive access to its just call
window.iframe_id.$
For example, window.view.$('div').hide() - hide all divs in iframe with id 'view'
But, it doesn't work in FF. For better compatibility you should use
$('#iframe_id')[0].contentWindow.$
Have you tried the classic, waiting for the load to complete using jQuery's builtin ready function?
$(document).ready(function() {
$('some selector', frames['nameOfMyIframe'].document).doStuff()
} );
K
I create a sample code . Now you can easily understand from different domain you can't access
content of iframe .. Same domain we can access iframe content
I share you my code , Please run this code
check the console . I print image src at console. There are four iframe , two iframe coming from same domain & other two from other domain(third party) .You can see two image src( https://www.google.com/logos/doodles/2015/googles-new-logo-5078286822539264.3-hp2x.gif
and
https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif
)
at console and also can see two permission error(
2
Error: Permission denied to access property 'document'
...irstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument...
) which is coming from third party iframe.
<body id="page-top" data-spy="scroll" data-target=".navbar-fixed-top">
<p>iframe from same domain</p>
<iframe frameborder="0" scrolling="no" width="500" height="500"
src="iframe.html" name="imgbox" class="iView">
</iframe>
<p>iframe from same domain</p>
<iframe frameborder="0" scrolling="no" width="500" height="500"
src="iframe2.html" name="imgbox" class="iView1">
</iframe>
<p>iframe from different domain</p>
<iframe frameborder="0" scrolling="no" width="500" height="500"
src="https://www.google.com/logos/doodles/2015/googles-new-logo-5078286822539264.3-hp2x.gif" name="imgbox" class="iView2">
</iframe>
<p>iframe from different domain</p>
<iframe frameborder="0" scrolling="no" width="500" height="500"
src="http://d1rmo5dfr7fx8e.cloudfront.net/" name="imgbox" class="iView3">
</iframe>
<script type='text/javascript'>
$(document).ready(function(){
setTimeout(function(){
var src = $('.iView').contents().find(".shrinkToFit").attr('src');
console.log(src);
}, 2000);
setTimeout(function(){
var src = $('.iView1').contents().find(".shrinkToFit").attr('src');
console.log(src);
}, 3000);
setTimeout(function(){
var src = $('.iView2').contents().find(".shrinkToFit").attr('src');
console.log(src);
}, 3000);
setTimeout(function(){
var src = $('.iView3').contents().find("img").attr('src');
console.log(src);
}, 3000);
})
</script>
</body>
If the code below doesn't work
$("#iFrame").contents().find("#someDiv").removeClass("hidden");
Here is the reliable way to make it work:
$(document).ready(function(){
setTimeout(
function () {
$("#iFrame").contents().find("#someDiv").removeClass("hidden");
},
300
);
});
This way the script will run after 300 miliseconds, so it'll get enough time for iFrame to be loaded and then the code will come into action. At times the iFrame doesn't load and script tries to execute before it. 300ms can be tweaked to anything else as per your needs.
For even more robustness:
function getIframeWindow(iframe_object) {
var doc;
if (iframe_object.contentWindow) {
return iframe_object.contentWindow;
}
if (iframe_object.window) {
return iframe_object.window;
}
if (!doc && iframe_object.contentDocument) {
doc = iframe_object.contentDocument;
}
if (!doc && iframe_object.document) {
doc = iframe_object.document;
}
if (doc && doc.defaultView) {
return doc.defaultView;
}
if (doc && doc.parentWindow) {
return doc.parentWindow;
}
return undefined;
}
and
...
var frame_win = getIframeWindow( frames['nameOfMyIframe'] );
if (frame_win) {
$(frame_win.contentDocument || frame_win.document).find('some selector').doStuff();
...
}
...
I ended up here looking for getting the content of an iframe without jquery, so for anyone else looking for that, it is just this:
document.querySelector('iframe[name=iframename]').contentDocument
This solution works same as iFrame. I have created a PHP script that can get all the contents from the other website, and most important part is you can easily apply your custom jQuery to that external content. Please refer to the following script that can get all the contents from the other website and then you can apply your cusom jQuery/JS as well. This content can be used anywhere, inside any element or any page.
<div id='myframe'>
<?php
/*
Use below function to display final HTML inside this div
*/
//Display Frame
echo displayFrame();
?>
</div>
<?php
/*
Function to display frame from another domain
*/
function displayFrame()
{
$webUrl = 'http://[external-web-domain.com]/';
//Get HTML from the URL
$content = file_get_contents($webUrl);
//Add custom JS to returned HTML content
$customJS = "
<script>
/* Here I am writing a sample jQuery to hide the navigation menu
You can write your own jQuery for this content
*/
//Hide Navigation bar
jQuery(\".navbar.navbar-default\").hide();
</script>";
//Append Custom JS with HTML
$html = $content . $customJS;
//Return customized HTML
return $html;
}
Related
How to block my website from loading in other sites iframes
How do I block my website from an iframe? For Instance YouTube cannot appear in a iframe it will say in place the owner of this website have blocked iframes. i am aware of the meta tag way like this <meta http-equiv="X-Frame-Options" content="deny"> howerver that does not work for me, is there any other way, i would prefer to use javascript and html no apachi php ajex or others please. this is the youtube iframe that i wish to block just with my site. also without .htaccess <!DOCTYPE html> <html> <head> <title>YouTube</title> </head> <body> <iframe width="50%" height="50%" src="http://www.youtube.com" > </iframe> </body>
My solution is to put in head or body tag <script type="text/javascript"> function PreventFrame() { try { if (window.top !== window.self) { document.write = ""; window.top.location = window.self.location; setTimeout(function() { document.body.innerHTML = ''; }, 0); window.self.onload = function() { document.body.innerHTML = ''; }; } } catch (err) {} } PreventFrame(); </script>
Get parent of clicked tag inside of iframe
I've an iframe that contain an HTML page.Now I want to get class of the parent item that clicked. this is my ifram: <iframe src="//example.com" id="frame" ></iframe> this is css: #frame{ width:380px; height:420px;} this is my script: $(document).ready(function() { var iframe = document.getElementById('frame'); var innerDoc = iframe.contentDocument || iframe.contentWindow.document.body; $(innerDoc).on('click', function(e) { var thisID = ((e.target).id); alert(thisID); alert(innerDoc.getElementById(thisID)); $(thisID).click(function() { var Allclassnames = $(thisID).parent(); console.log(Allclassnames); }); }); }); but it return the item was clicked only.how to fix it? Demo:DEMO NOTE:these are in a same domain.maybe below DEMO not worked for this reason.but I'm sure that my HTML is inside of the same domain with my web site. thank you.
Add sandbox attributes to the iframe <iframe src="/example.html" id="frame" sandbox="allow-scripts allow-same-origin"></iframe> Change the script to <script> $('#frame').load(function() { $('#frame').contents().on('click', function(e) { var thisID = ((e.target).id); alert(thisID); alert($('#'+thisID,this)); $('#'+thisID,this).click(function() { var Allclassnames = $(this).parent(); console.log(Allclassnames); }); }); }); </script> Make sure that every element in frame doc. have some id or else the alert() may throw an error. To see the console message of iframe you need to change the scope from the scope dropdown , it's in console tab besides the filter icon in the chrome developer tools.
You cannot interact with the contents of an iframe unless it is on the same domain as the parent document. See: https://en.wikipedia.org/wiki/Same-origin_policy
Is it safe to use '*' as the origin of a message from inside an iframe?
The problem was, that I had an <iframe> with dynamically changing content. I couldn't find any other way to dynamically change the height of the <iframe> element than sending new height each time when it changes to the bloggers website by parent.postMessage. The solution works (maybe it can help others, but the thing is that I'm not sure if I have done it in a safe way. I just want to ask if it's safe to use window.parent.postMessage('Some message', '*') in that way? Embeded site: <script type="text/javascript"> var framesHeight = 0; setInterval(function(){ var newFramesHeight = window.document.getElementsByTagName('html')[0].offsetHeight; if (newFramesHeight !== framesHeight) { window.parent.postMessage(newFramesHeight, '*'); framesHeight = newFramesHeight; } }, 500); </script> As you can see, each time when the hight changes I send a new message. On the bloggers website I want to embed this: <script> window.addEventListener('message', function (evt) { if (evt.origin === 'http://mypage.com' && !isNaN(evt.data)) { document.getElementById('embedID').style.height = evt.data+'px'; } }, false); </script> <iframe id="embedID" src="http://mypage.com/embed/11" frameborder="0" style="width: 100%; height: 100%;" scrolling="no"></iframe>
Get A tag href from nested iframe [duplicate]
I would like to manipulate the HTML inside an iframe using jQuery. I thought I'd be able to do this by setting the context of the jQuery function to be the document of the iframe, something like: $(function(){ //document ready $('some selector', frames['nameOfMyIframe'].document).doStuff() }); However this doesn't seem to work. A bit of inspection shows me that the variables in frames['nameOfMyIframe'] are undefined unless I wait a while for the iframe to load. However, when the iframe loads the variables are not accessible (I get permission denied-type errors). Does anyone know of a work-around to this?
If the <iframe> is from the same domain, the elements are easily accessible as $("#iFrame").contents().find("#someDiv").removeClass("hidden"); Reference
I think what you are doing is subject to the same origin policy. This should be the reason why you are getting permission denied type errors.
You could use .contents() method of jQuery. The .contents() method can also be used to get the content document of an iframe, if the iframe is on the same domain as the main page. $(document).ready(function(){ $('#frameID').load(function(){ $('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!'); }); });
If the iframe src is from another domain you can still do it. You need to read the external page into PHP and echo it from your domain. Like this: iframe_page.php <?php $URL = "http://external.com"; $domain = file_get_contents($URL); echo $domain; ?> Then something like this: display_page.html <html> <head> <title>Test</title> </head> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script> <script> $(document).ready(function(){ cleanit = setInterval ( "cleaning()", 500 ); }); function cleaning(){ if($('#frametest').contents().find('.selector').html() == "somthing"){ clearInterval(cleanit); $('#selector').contents().find('.Link').html('ideate tech'); } } </script> <body> <iframe name="frametest" id="frametest" src="http://yourdomain.com/iframe_page.php" ></iframe> </body> </html> The above is an example of how to edit an external page through an iframe without the access denied etc...
Use iframe.contentWindow.document instead of iframe.contentDocument
I find this way cleaner: var $iframe = $("#iframeID").contents(); $iframe.find('selector');
You need to attach an event to an iframe's onload handler, and execute the js in there, so that you make sure the iframe has finished loading before accessing it. $().ready(function () { $("#iframeID").ready(function () { //The function below executes once the iframe has finished loading $('some selector', frames['nameOfMyIframe'].document).doStuff(); }); }; The above will solve the 'not-yet-loaded' problem, but as regards the permissions, if you are loading a page in the iframe that is from a different domain, you won't be able to access it due to security restrictions.
You can use window.postMessage to call a function between page and his iframe (cross domain or not). Documentation page.html <!DOCTYPE html> <html> <head> <title>Page with an iframe</title> <meta charset="UTF-8" /> <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script> <script> var Page = { id:'page', variable:'This is the page.' }; $(window).on('message', function(e) { var event = e.originalEvent; if(window.console) { console.log(event); } alert(event.origin + '\n' + event.data); }); function iframeReady(iframe) { if(iframe.contentWindow.postMessage) { iframe.contentWindow.postMessage('Hello ' + Page.id, '*'); } } </script> </head> <body> <h1>Page with an iframe</h1> <iframe src="iframe.html" onload="iframeReady(this);"></iframe> </body> </html> iframe.html <!DOCTYPE html> <html> <head> <title>iframe</title> <meta charset="UTF-8" /> <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script> <script> var Page = { id:'iframe', variable:'The iframe.' }; $(window).on('message', function(e) { var event = e.originalEvent; if(window.console) { console.log(event); } alert(event.origin + '\n' + event.data); }); $(window).on('load', function() { if(window.parent.postMessage) { window.parent.postMessage('Hello ' + Page.id, '*'); } }); </script> </head> <body> <h1>iframe</h1> <p>It's the iframe.</p> </body> </html>
I prefer to use other variant for accessing. From parent you can have a access to variable in child iframe. $ is a variable too and you can receive access to its just call window.iframe_id.$ For example, window.view.$('div').hide() - hide all divs in iframe with id 'view' But, it doesn't work in FF. For better compatibility you should use $('#iframe_id')[0].contentWindow.$
Have you tried the classic, waiting for the load to complete using jQuery's builtin ready function? $(document).ready(function() { $('some selector', frames['nameOfMyIframe'].document).doStuff() } ); K
I create a sample code . Now you can easily understand from different domain you can't access content of iframe .. Same domain we can access iframe content I share you my code , Please run this code check the console . I print image src at console. There are four iframe , two iframe coming from same domain & other two from other domain(third party) .You can see two image src( https://www.google.com/logos/doodles/2015/googles-new-logo-5078286822539264.3-hp2x.gif and https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif ) at console and also can see two permission error( 2 Error: Permission denied to access property 'document' ...irstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument... ) which is coming from third party iframe. <body id="page-top" data-spy="scroll" data-target=".navbar-fixed-top"> <p>iframe from same domain</p> <iframe frameborder="0" scrolling="no" width="500" height="500" src="iframe.html" name="imgbox" class="iView"> </iframe> <p>iframe from same domain</p> <iframe frameborder="0" scrolling="no" width="500" height="500" src="iframe2.html" name="imgbox" class="iView1"> </iframe> <p>iframe from different domain</p> <iframe frameborder="0" scrolling="no" width="500" height="500" src="https://www.google.com/logos/doodles/2015/googles-new-logo-5078286822539264.3-hp2x.gif" name="imgbox" class="iView2"> </iframe> <p>iframe from different domain</p> <iframe frameborder="0" scrolling="no" width="500" height="500" src="http://d1rmo5dfr7fx8e.cloudfront.net/" name="imgbox" class="iView3"> </iframe> <script type='text/javascript'> $(document).ready(function(){ setTimeout(function(){ var src = $('.iView').contents().find(".shrinkToFit").attr('src'); console.log(src); }, 2000); setTimeout(function(){ var src = $('.iView1').contents().find(".shrinkToFit").attr('src'); console.log(src); }, 3000); setTimeout(function(){ var src = $('.iView2').contents().find(".shrinkToFit").attr('src'); console.log(src); }, 3000); setTimeout(function(){ var src = $('.iView3').contents().find("img").attr('src'); console.log(src); }, 3000); }) </script> </body>
If the code below doesn't work $("#iFrame").contents().find("#someDiv").removeClass("hidden"); Here is the reliable way to make it work: $(document).ready(function(){ setTimeout( function () { $("#iFrame").contents().find("#someDiv").removeClass("hidden"); }, 300 ); }); This way the script will run after 300 miliseconds, so it'll get enough time for iFrame to be loaded and then the code will come into action. At times the iFrame doesn't load and script tries to execute before it. 300ms can be tweaked to anything else as per your needs.
For even more robustness: function getIframeWindow(iframe_object) { var doc; if (iframe_object.contentWindow) { return iframe_object.contentWindow; } if (iframe_object.window) { return iframe_object.window; } if (!doc && iframe_object.contentDocument) { doc = iframe_object.contentDocument; } if (!doc && iframe_object.document) { doc = iframe_object.document; } if (doc && doc.defaultView) { return doc.defaultView; } if (doc && doc.parentWindow) { return doc.parentWindow; } return undefined; } and ... var frame_win = getIframeWindow( frames['nameOfMyIframe'] ); if (frame_win) { $(frame_win.contentDocument || frame_win.document).find('some selector').doStuff(); ... } ...
I ended up here looking for getting the content of an iframe without jquery, so for anyone else looking for that, it is just this: document.querySelector('iframe[name=iframename]').contentDocument
This solution works same as iFrame. I have created a PHP script that can get all the contents from the other website, and most important part is you can easily apply your custom jQuery to that external content. Please refer to the following script that can get all the contents from the other website and then you can apply your cusom jQuery/JS as well. This content can be used anywhere, inside any element or any page. <div id='myframe'> <?php /* Use below function to display final HTML inside this div */ //Display Frame echo displayFrame(); ?> </div> <?php /* Function to display frame from another domain */ function displayFrame() { $webUrl = 'http://[external-web-domain.com]/'; //Get HTML from the URL $content = file_get_contents($webUrl); //Add custom JS to returned HTML content $customJS = " <script> /* Here I am writing a sample jQuery to hide the navigation menu You can write your own jQuery for this content */ //Hide Navigation bar jQuery(\".navbar.navbar-default\").hide(); </script>"; //Append Custom JS with HTML $html = $content . $customJS; //Return customized HTML return $html; }
Random websites not display on iframe
This code is generating a random link from variable but that link is not opening in iframe I need to display random links in iframe whenever the button is clicked. How to do that? <html> <script> var cat1 = [ "http://arborjs.org", "http://cartodb.com", "http://vis4.net/labs/185" ]; var myFrame = document.getElementById("frame"); getRandomUrl(myFrame); function getRandomUrl(myFrame) { var index = Math.floor(Math.random()*cat1.length); var url = cat1[index]; document.getElementById('frame').src = url; } btn.addEventListener("click", function() { getRandomUrl(myFrame); }); </script> <body> <button id="btn">Click</button> <br> <iframe id="frame" src="" style="width:500px; height: 500px"></iframe> </body> </html>
You have to put the script tag after all your HTML or wait for the window to load. Also, you're calling a function before it's defined. This code is generating a random link from variable I don't think this is happening, if you open your console it should tell you the function and iframe are both undefined, as I stated above.