Accessing Iframe Variable in Parent With Javascript - javascript

I'm aware there are incredibly similar questions on Stack Overflow already for this, but I've tried MANY of them, and am just getting nothing. I'm trying to grab a variable from the child iframe to use in the parent window.
In child.html head tag
<script type="text/javascript">
var myVar="1";
</script>
In parent.html
<script type="text/javascript">
function load()
{
var scroll="0";
scroll = window.myIframe.myVar;
if (scroll == "0") DO SOMETHING;
else DO SOMETHING ELSE;
}
</script>
<iframe src="child.html" name="myIframe" onload="load()">
<p>Your browser does not support iframes.</p>
</iframe>
And no matter what I try, I cannot get scroll to grab the myVar variable from the child iframe. This is nearly verbatim of examples on Stack Overflow and other forums that people say work perfectly; any ideas what I'm doing wrong?
Edit: They are on the same domain.

Try to access oad() from inside child when the page loads in iframe.
Add in child:
<body onload="parent.load()">
Also, you can change the code to pass and get the variable as parameter in load(prm) .

I tried your code offline and i get an error "unsafe access" while accessing
window.myFrame
local pages can be tricky, however when i put the same files online they work well, domains and ports match.
still i think its a bit weird using name="..." on the iframe, i would be using ID, but that doesn't seem to bother chrome and i got access to the variable with either onload on parent or child.

Related

document.querySelector works in console but not on realtime

I'm creating a simple html page with one audio player inside an iframe.
I need to enamble kind of autoplay for desktop and mobile.
The player is this one:
<div style="width: 100%"><iframe src="https://players.rcast.net/fixedbar1/66549" frameborder="0" scrolling="no" autoplay style="width: 100%"></iframe></div>
I put this block on the bottom of the html page:
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
// this function runs when the DOM is ready
setTimeout(function(){
document.querySelector('.play-btn').click();
},3000); //delay is in milliseconds
});
</script>
Using firefox console document.querySelector('.play-btn').click(); works fine, but on runtime i get:
Uncaught TypeError: document.querySelector(...) is null
Any ideas or best ways?
Thanks,
Red
You can do whatever you want in the console but you would only be able to access iframe content programmatically if your iframe domain matches your current domain.
That being said, you can:
Select the iframe, then run query selector on the iframe (you don't even need jQuery for it):
const iframeElement = document.querySelector('iframe');
iframeElement.querySelector('.play-btn').click();
Tips:
You can also play the video/music directly by calling play() on
the media elements. So you can cut out stimulating click on
the button.
querySelector is slower than getElementById, you can assign an id attribute to your iframe/button/media element and find it directly.
It will also help you avoid bugs because querySelector returns the first match. So in case you have multiple iframe or multiple elements with the class .play-btn, it can lead to unexpected behaviour.
you should select iframe at first and get its content window to access all elements on it.
const myIframe = document.querySelector('#iframe_id')
const myIframeDocument =myIframe.contentWindow.document
const myElement = myIframeDocument.body.querySelector('#target_element')
it is noticeable that the iframe should be loaded completely before your process and also domain conflict
Hope this helps:
<iframe id="video1" width="450" height="280" src="http://www.youtube.com/embed/TJ2X4dFhAC0?enablejsapi" frameborder="0" allowtransparency="true" allowfullscreen></iframe>
Play button
<script>
$("#playvideo").click(function(){
$("#video1")[0].src += "?autoplay=1";
});
</script>
I found this on Grepper, but it was from another Stack Overflow post.
If that doesn't help I found a different post that seems to be more related to the error.

JavaScript: Detect source change from iframe

This might be a long shot but I was wondering if anyone knew if there was a way to detect (with Javascript or JQuery) if an iframes source has changed - ie: if a user changes the page within an iframe.
I want to write something like:
if (iframesource == http://www.site.com/urlA){
do something
}
else if (iframesource == http://www.site.com/urlB){
do something different
}
I already know the src attribute for the iframe element (<iframe src="http://www.site.com">) does not change if the page changes within the site so using JQuery to detect the attribute is out.
would anyone know if this is possible? Any advice would be greatly appreciated! Thanks
OK basically after loads of research I have found out that this only works if the iframe is pointing to a URL within your existing site or server. If you are pointing to another site (say YouTube) it will not work.
The best way to transfer information from one site to another is still with JSON.
You will need to build a javascript function that does a few things:
onload.
obtains src value by element id.
passes this into temp_object
enter recursive function with a set_timeout(100ms) say.
compare temp_object to object.
if true, do something, temp_object = object.
#EDIT -----> anti-sop anti-xss
<html>
<head>
<script type="text/javascript">
function GetIFrameUrl()
{
alert('url = ' + document.frames['frame1'].location.href);
}
</script>
</head>
<body>
Find the iFrame URL
<iframe name="frame1" src="http://www.google.com" width="100%" height="400"></iframe>
</body>
</html>
Getting the current src of an Iframe using JQuery

How can I launch a PARENT jQuery function?

I'm trying to figure out how to launch a function from an iframe but the following example won't work, any ideas?
<input class='reply' onclick='parent.replytopost()' type='button' value='Reply' />
PARENT PAGE FUNCTION (In the body if that makes a difference):
<script>
function replytopost(){
alert("test");
parent.document.getElementById('mainbar').innerHTML = "TEST";
parent.document.getElementById('post_reply').show();
}
</script>
This might become an issue with security-tightened browsers (such as Safari).
I ran against the same type of problem recently, and I'm now a happy user of window.postMessage.
You will still have to reference it using window.parent but this will prevent the vast majority of issues to happen.
It works for me. Look here
Why do you call parent.* in non-iframe replytopost script?
Will window.opener work for you? I know it works from a parent to a newWindow. I don't know about iframe.
http://www.w3schools.com/jsref/prop_win_opener.asp

Calling a parent window function from an iframe

I want to call a parent window JavaScript function from an iframe.
<script>
function abc()
{
alert("sss");
}
</script>
<iframe id="myFrame">
<a onclick="abc();" href="#">Call Me</a>
</iframe>
<a onclick="parent.abc();" href="#" >Call Me </a>
See window.parent
Returns a reference to the parent of the current window or subframe.
If a window does not have a parent, its parent property is a reference to itself.
When a window is loaded in an <iframe>, <object>, or <frame>, its parent is the window with the element embedding the window.
Window.postMessage()
This method safely enables cross-origin communication.
And if you have access to parent page code then any parent method can be called as well as any data can be passed directly from Iframe. Here is a small example:
Parent page:
if (window.addEventListener) {
window.addEventListener("message", onMessage, false);
}
else if (window.attachEvent) {
window.attachEvent("onmessage", onMessage, false);
}
function onMessage(event) {
// Check sender origin to be trusted
if (event.origin !== "http://example.com") return;
var data = event.data;
if (typeof(window[data.func]) == "function") {
window[data.func].call(null, data.message);
}
}
// Function to be called from iframe
function parentFunc(message) {
alert(message);
}
Iframe code:
window.parent.postMessage({
'func': 'parentFunc',
'message': 'Message text from iframe.'
}, "*");
// Use target origin instead of *
UPDATES:
Security note:
Always provide a specific targetOrigin, NOT *, if you know where the other window's document should be located. Failing to provide a specific target discloses the data you send to any interested malicious site (comment by ZalemCitizen).
References:
Cross-document messaging
Window.postMessage()
Can I Use
I recently had to find out why this didn't work too.
The javascript you want to call from the child iframe needs to be in the head of the parent. If it is in the body, the script is not available in the global scope.
<head>
<script>
function abc() {
alert("sss");
}
</script>
</head>
<body>
<iframe id="myFrame">
<a onclick="parent.abc();" href="#">Click Me</a>
</iframe>
</body>
Hope this helps anyone that stumbles upon this issue again.
You can use
window.top
see the following.
<head>
<script>
function abc() {
alert("sss");
}
</script>
</head>
<body>
<iframe id="myFrame">
<a onclick="window.top.abc();" href="#">Click Me</a>
</iframe>
</body>
I have posted this as a separate answer as it is unrelated to my existing answer.
This issue recently cropped up again for accessing a parent from an iframe referencing a subdomain and the existing fixes did not work.
This time the answer was to modify the document.domain of the parent page and the iframe to be the same. This will fool the same origin policy checks into thinking they co-exist on exactly the same domain (subdomains are considered a different host and fail the same origin policy check).
Insert the following to the <head> of the page in the iframe to match the parent domain (adjust for your doctype).
<script>
document.domain = "mydomain.com";
</script>
Please note that this will throw an error on localhost development, so use a check like the following to avoid the error:
if (!window.location.href.match(/localhost/gi)) {
document.domain = "mydomain.com";
}
parent.abc() will only work on same domain due to security purposes. i tried this workaround and mine worked perfectly.
<head>
<script>
function abc() {
alert("sss");
}
// window of the iframe
var innerWindow = document.getElementById('myFrame').contentWindow;
innerWindow.abc= abc;
</script>
</head>
<body>
<iframe id="myFrame">
<a onclick="abc();" href="#">Click Me</a>
</iframe>
</body>
Hope this helps. :)
Another addition for those who need it. Ash Clarke's solution does not work if they are using different protocols so be sure that if you are using SSL, your iframe is using SSL as well or it will break the function. His solution did work for the domains itself though, so thanks for that.
The solution given by Ash Clarke for subdomains works great, but please note that you need to include the document.domain = "mydomain.com"; in both the head of the iframe page and the head of the parent page, as stated in the link same origin policy checks
An important extension to the same origin policy implemented for JavaScript DOM access (but not for most of the other flavors of same-origin checks) is that two sites sharing a common top-level domain may opt to communicate despite failing the "same host" check by mutually setting their respective document.domain DOM property to the same qualified, right-hand fragment of their current host name.
For example, if http://en.example.com/ and http://fr.example.com/ both set document.domain to "example.com", they would be from that point on considered same-origin for the purpose of DOM manipulation.
With Firefox and Chrome you can use :
<a href="whatever" target="_parent" onclick="myfunction()">
If myfunction is present both in iframe and in parent, the parent one will be called.
While some of these solutions may work, none of them follow best practices. Many assign global variables and you may find yourself making calls to multiple parent variables or functions, leading to a cluttered, vulnerable namespace.
To avoid this, use a module pattern. In the parent window:
var myThing = {
var i = 0;
myFunction : function () {
// do something
}
};
var newThing = Object.create(myThing);
Then, in the iframe:
function myIframeFunction () {
parent.myThing.myFunction();
alert(parent.myThing.i);
};
This is similar to patterns described in the Inheritance chapter of Crockford's seminal text, "Javascript: The Good Parts." You can also learn more at w3's page for Javascript's best practices. https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals
A plugin helper gist that allows the parent window to call the child iframe windows functions and vice-versa, but all calls are asynchronous.
https://gist.github.com/clinuxrulz/77f341832c6025bf10f0b183ee85e072
This will also work cross-origin, but can only call functions that you export to the iframe from the parent and the parent window can only call funtions the iframe exports.

Close iframe cross domain

I am trying to do something similar to the Clipper application here http://www.polyvore.com/cgi/clipper
I can make the iframe appear in another website (cross domain). But I cannot make the "close" button to work.
This is what I used but it doesn't work for cross domain (basically remove the iframe element)
window.parent.document.getElementById('someId').parentNode.removeChild(window.parent.document.getElementById('someId'));
Can you help? Thanks.
You should use a library that abstracts this (e.g. http://easyxdm.net/wp/ , not tested). Fragment ID messaging may not work in all browsers, and there are better approaches, such as postMessage.
However, your example (Clipper) is using a hack called fragment id messaging. This can be cross-browser, provided the page containing your iframe is the top level. In other words, there are a total of two levels. Basically, the child sets the fragment of the parent, and the parent watches for this.
This is a similar approach to Clipper's:
parent.html
<html>
<head>
<script type="text/javascript">
function checkForClose()
{
if(window.location.hash == "#close_child")
{
var someIframe = document.getElementById("someId");
someIframe.parentNode.removeChild(someIframe);
}
else
{
setTimeout(checkForClose, 1000)
}
}
setTimeout(checkForClose, 1000);
</script>
</head>
<body>
<iframe name="someId" id="someId" src="child.html" height="800" width="600">foo</iframe>
</body>
</html>
child.html:
<html>
<head>
<script type="text/javascript">
setTimeout(function(){window.parent.location.hash = "close_child";}, 5000);
</script>
<body style="background-color: blue"></body>
</html>
EDIT2: Cross-domain and independently controlled are different. I dug into the (heavily minified/obfuscated) Polyvore code to see how it works (incidentally, it doesn't in Firefox). First remember that bookmarklets, such as the Clipper, live in the context of the page open when they start. In this case, the bookmarklet loads a script , which in turn runs an init function which generates an iframe, but also runs:
Event.addListener(Event.XFRAME, "done", cancel);
If you digg into addListener, you'll find (beautified):
if (_1ce2 == Event.XFRAME) {
if (!_1cb3) {
_1cb3 = new Monitor(function () {
return window.location.hash;
},
100);
Event.addListener(_1cb3, "change", onHashChange);
}
}
cancel includes:
removeNode(iframe);
Now, the only remaining piece is that the iframe page loads another script with a ClipperForm.init function that includes:
Event.addListener($("close"), "click", function () {
Event.postMessage(window.parent, _228d, "done");
});
So we see clearly they are using fragment ID messaging.
Try hiding the contents of the iframe, and don't worry about actually getting rid of the iframe element in the parent.
There is another implementation of the old hash hack. It's backwards compatible, easy javascript-only, and very easy to implement:
http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/

Categories