how to call a parent script from an iframe [duplicate] - javascript

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.

Related

Remove id from iframe

I have an iframe of a certain page from a site that I'm using, but I don't want all the parts of that page to be displayed with the iframe. Particularly, there's a navigation sidebar on the page that I don't want to be in the iframe. I'm trying to achieve this with the javascript seen below, but I can't quite figure it out.
<iframe width="800" height="800" src="scores/new?site_id=193">
<script>
var element = document.getElementById("sidebar-wrapper");
element.parentNode.removeChild(element);
</script>
</iframe>
For security reasons you can't run javascript through iframes. There are some exceptions if you're on the same domain but for the most part you should really avoid it.
If the iframe isn't a site you can control then there's pretty much nothing you can do. If you do control the other site and it's a different domain you might be able to work with the postMessage functions.
Edit: Check out the docs that Mozilla has up here https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
You'd need to create a listener on the inside that handles a message and hides your sidebar. Then on the parent send a message to the iframe to trigger that function.
Parent:
var iframe = document.getElementById('#iframeID');
iframe.contentWindow.postMessage('iframeTrigger');
Iframe:
window.addEventListener('iframeTrigger', hideSidebar);
function hideSidebar() {
//do stuff
}
You can insert a control in the iframed page
//inside the iframed page
var iframe = (function() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
})();
if(iframe === true) {
var element = document.getElementById("sidebar-wrapper");
element.parentNode.removeChild(element);
}
Hope this could suit your need.
This should work theoretically, and it works in console. But this doesn't work in the HTML, although you are trying it from the same domain, because of security reasons. I just wanted to tell my view and I tried this:
<iframe src="http://output.jsbin.com/figujeyiyo" frameborder="0" id="ifrm">
Sorry, iframes not supported.
</iframe>
<script>
console.log(document.getElementById("ifrm").contentDocument.documentElement.getElementsByTagName("div"));
e = document.getElementById("ifrm").contentDocument.documentElement.getElementsByTagName("div")[0];
console.log(e);
e.parentNode.removeChild(element);
</script>
You need to execute the code when the page loads, you can do it like this:
document.addEventListener('DOMContentLoaded', function() {
var element = document.getElementById("sidebar-wrapper");
element.parentNode.removeChild(element);
});

Block my iframe from executing top.location.href inside its javascript? [duplicate]

Some websites have code to "break out" of IFRAME enclosures, meaning that if a page A is loaded as an IFRAME inside an parent page P some Javascript in A redirects the outer window to A.
Typically this Javascript looks something like this:
<script type="text/javascript">
if (top.location.href != self.location.href)
top.location.href = self.location.href;
</script>
My question is: As the author of the parent page P and not being the author of the inner page A, how can I prevent A from doing this break-out?
P.S. It seems to me like it ought to be a cross-site security violation, but it isn't.
With HTML5 the iframe sandbox attribute was added. At the time of writing this works on Chrome, Safari, Firefox and recent versions of IE and Opera but does pretty much what you want:
<iframe src="url" sandbox="allow-forms allow-scripts"></iframe>
If you want to allow top-level redirects specify sandbox="allow-top-navigation".
I use the sandbox attribute on the iframe element:
allow-forms allow form submission
allow-popups allows popups
allow-pointer-lock allows pointer lock
allow-same-origin allows the document to maintain its origin
allow-scripts allows JavaScript execution, and also allows features to trigger automatically
allow-top-navigation allows the document to break out of the frame by navigating the top-level window
Top navigation is what you want to prevent, so leave that out and it will not be allowed. Anything left out will be blocked
ex.
<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="http://www.example.com"</iframe>
Try using the onbeforeunload property, which will let the user choose whether he wants to navigate away from the page.
Example: https://developer.mozilla.org/en-US/docs/Web/API/Window.onbeforeunload
In HTML5 you can use sandbox property. Please see Pankrat's answer below.
http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
After reading the w3.org spec. I found the sandbox property.
You can set sandbox="", which prevents the iframe from redirecting. That being said it won't redirect the iframe either. You will lose the click essentially.
Example here: http://jsfiddle.net/ppkzS/1/
Example without sandbox: http://jsfiddle.net/ppkzS/
I know it has been a long time since question was done but here is my improved version it will wait 500ms for any subsequent call only when the iframe is loaded.
<script type="text/javasript">
var prevent_bust = false ;
var from_loading_204 = false;
var frame_loading = false;
var prevent_bust_timer = 0;
var primer = true;
window.onbeforeunload = function(event) {
prevent_bust = !from_loading_204 && frame_loading;
if(from_loading_204)from_loading_204 = false;
if(prevent_bust){
prevent_bust_timer=500;
}
}
function frameLoad(){
if(!primer){
from_loading_204 = true;
window.top.location = '/?204';
prevent_bust = false;
frame_loading = true;
prevent_bust_timer=1000;
}else{
primer = false;
}
}
setInterval(function() {
if (prevent_bust_timer>0) {
if(prevent_bust){
from_loading_204 = true;
window.top.location = '/?204';
prevent_bust = false;
}else if(prevent_bust_timer == 1){
frame_loading = false;
prevent_bust = false;
from_loading_204 = false;
prevent_bust_timer == 0;
}
}
prevent_bust_timer--;
if(prevent_bust_timer==-100) {
prevent_bust_timer = 0;
}
}, 1);
</script>
and onload="frameLoad()" and onreadystatechange="frameLoad();" must be added to the frame or iframe.
Since the page you load inside the iframe can execute the "break out" code with a setInterval, onbeforeunload might not be that practical, since it could flud the user with 'Are you sure you want to leave?' dialogs.
There is also the iframe security attribute which only works on IE & Opera
:(
In my case I want the user to visit the inner page so that server will see their ip as a visitor. If I use the php proxy technique I think that the inner page will see my server ip as a visitor so it is not good. The only solution I got so far is wilth onbeforeunload.
Put this on your page:
<script type="text/javascript">
window.onbeforeunload = function () {
return "This will end your session";
}
</script>
This works both in firefox and ie, thats what I tested for.
you will find versions using something like evt.return(whatever) crap... that doesn't work in firefox.
try:
<iframe sandbox=" "></iframe>
By doing so you'd be able to control any action of the framed page, which you cannot. Same-domain origin policy applies.

can I catch exception of Iframe in parent window of Iframe

I have an IFrame in a page and IFrame has some JavaScript. At run time JavaScript in IFrame gives exception which i want to catch on parent window. How to do that?
<html>
<head>
<script type="text/javascript">
var frm123 = document.getElementById("frm123");
frm123.contentWindow.onerror = function() {
alert('error caught');
}
function loadData() {
var oRTE = document.getElementById("frm123").contentWindow.document;
oRTE.open();
oRTE.write(txt123.value);
oRTE.close();
}
</script>
</head>
<body>
<input type="button" onclick="loadData();" value="load">
<input type="text" id="txt123">
<iframe id = "frm123" >
</body>
</html>
The answer depends on whether or not you have control of the iframe code, and whether or not it is the same domain.
If same domain then you can do the following to set the error handling function from the wrapping document:
document.getElementById("myiframe").contentWindow.onerror=function() {
alert('error!!');
return false;
}
make sure you wait for the iframe to finish loading before setting the error handler.
If it's not the same domain but you have control of the iframe content (both domains are under your control), you can communicate with the outer frame by using a cross domain communication framework (google it or build it yourself), i.e. catch the error in the iframe by setting the onerror handler from within the iframe and send it through the framework to the outer document.
If it's not the same domain and you don't have control of the iframe, there's no way for the outer document to know what's going on inside it because of security constraints.
There may be few possible causes for .onError() function not to work it may be because of cross domain URL's for this you should implement a check before actulally laoding the iFrame and for that use
var url = "google.com"
var loading_url = "/empty.html"
document.getElementById("iframe").src = loading_url;
$.ajax({
url: url,
type: 'GET',
complete: function(e, xhr, settings){
if(e.status === 200){
document.getElementById("iframe").src = url;
}
}
});
This will not work cross domain, the status code is 0 in those cases.
One more thing to check is .onError() handler please check from below sample if it matches your conditions
How can I handle errors in loading an iframe?
There are many other options or tweaks to handle this kind of errors :
if (frameDoc.title == 'title of page after expection occur')
will also do the work using on .onLoad() event of iFrame.
The only way is if the frame is on the same domain, in which case you can do, from parent:
iframe.contentWindow.onerror = function(){
// handle error
}

Get IFrame's document, from JavaScript in main document

I have this HTML code:
<html>
<head>
<script type="text/javascript">
function GetDoc(x)
{
return x.document ||
x.contentDocument ||
x.contentWindow.document;
}
function DoStuff()
{
var fr = document.all["myframe"];
while(fr.ariaBusy) { }
var doc = GetDoc(fr);
if (doc == document)
alert("Bad");
else
alert("Good");
}
</script>
</head>
<body>
<iframe id="myframe" src="http://example.com" width="100%" height="100%" onload="DoStuff()"></iframe>
</body>
</html>
The problem is that I get message "Bad". That mean that the document of iframe is not got correctly, and what is actualy returned by GetDoc function is the parent document.
I would be thankful, if you told where I do my mistake. (I want to get document hosted in IFrame.)
Thank you.
You should be able to access the document in the IFRAME using the following code:
document.getElementById('myframe').contentWindow.document
However, you will not be able to do this if the page in the frame is loaded from a different domain (such as google.com). This is because of the browser's Same Origin Policy.
The problem is that in IE (which is what I presume you're testing in), the <iframe> element has a document property that refers to the document containing the iframe, and this is getting used before the contentDocument or contentWindow.document properties. What you need is:
function GetDoc(x) {
return x.contentDocument || x.contentWindow.document;
}
Also, document.all is not available in all browsers and is non-standard. Use document.getElementById() instead.
In case you get a cross-domain error:
If you have control over the content of the iframe - that is, if it is merely loaded in a cross-origin setup such as on Amazon Mechanical Turk - you can circumvent this problem with the <body onload='my_func(my_arg)'> attribute for the inner html.
For example, for the inner html, use the this html parameter (yes - this is defined and it refers to the parent window of the inner body element):
<body onload='changeForm(this)'>
In the inner html :
function changeForm(window) {
console.log('inner window loaded: do whatever you want with the inner html');
window.document.getElementById('mturk_form').style.display = 'none';
</script>
You can also use:
document.querySelector('iframe').contentDocument

Calling A Javascript function from Silverlight

I'm attempting to call a javascript function (in our code) from a silverlight control. I'm attempting to call the function via:
HtmlPage.Window.Invoke("showPopup", new string[] { "http://www.example.com" });
and I get the error "Failed to Invoke: showPopup"
I can call HtmlPage.Window.Invoke("alert", new string[]{"test"}); without issue, but not my own function.
I can also open up the page in question in the IE developer tools and manually call showPopup("http://www.example.com") and it works as expected.
So the js function works, and the Silverlight binary can find other js functions. What am I missing here?
Additional Notes:
The function call is in a button click event handler, so it happens after the page (and the script) have been loaded)
Aha! I figured it out. Our app uses an iframe, so the rendered html looks something like this
<html>
<head></head>
<body>
Stuff
<iframe>
<html>
<head></head>
<body>Other Stuff</body>
</html>
</iframe>
<body>
</html>
And the Silverlight control in question is in the iframe. The problem was that the file that contained the showPopup function was referenced in the outer <head> (why I could call the function with the IE toolbar) but not the inner <head>. Adding a reference to the file in the in-the-iframe <head> solved the problem.
Sort of anticlimactic, but thanks for all the help.
Actually referencing the script again from the iframe is not the most efficient way to reference code contained in the parent. If your function is called "showPopup", you can insert this in your iframe:
<script type="text/javascript">
var showPopup = parent.showPopup;
</script>
And voilĂ . The explanation for this is that all "global" functions and objects are part of this "global namespace"... which is the "window" object. So if you're trying to access "global" functions from a child, you need to either call the function on the parent (e.g parent.showPopup('....')) or declare a local alias for it (which is what we do in the above example).
Cheers!
Is the showPopup javascript function on the same html or aspx page as the Silverlight control? You will normally get the "Failed to Invoke ..." error if the javascript function does not exist:
HtmlPage.Window.Invoke("functionThatDoesNotExist", new [] { "Testing" });
What browser are you using when you are getting this problem?
Are you using the latest version of Silverlight?
Are you using the ScriptableType attrbiute anywhere?
Is it possible to list the code for a short but complete program that causes this problem to happen on your machine...
Make sure your script is fully loaded before trying to invoke functions from it.
Here's how I do it. But I'm creating silverlight without visual studio. I just have raw html, xaml, and js (javascript). Notice MouseLeftButtonUp and it's value "LandOnSpace"
<Canvas x:Name="btnLandOnSpace" Background="LightGreen" MouseLeftButtonUp="LandOnSpace"
Cursor="Hand" Canvas.Top ="0" Width="70" Height="50">
<TextBlock Text="LandOnSpace" />
</Canvas>
function LandOnSpace(sender, e) { //on server
if (!ShipAnimateActive && !blnWaitingOnServer) {
blnWaitingOnServer = true;
RunServerFunction("/sqgame/getJSLLandOnSpace");
ShowWaitingBox();
};
else {
alert('Waiting on server.');
};
}
I had the same problem in VS 2010 with SL 4. I had created a few methods and put them into one single JS file. However this file had not been added to the head section of the ASPX file. Adding it solved the problem. The difference is that though I did not have a separate head section in the iframe, I had the problem and it got solved.

Categories

Resources