I have a situation where I have web apps on two different servers, where App1 contains App2 in an IFrame. Any links in App2 can have target="_parent"
attribute, which allow those links to open in the top window. However, I can't find any way to get the same behavior in Javascript. I found this page, which claims that the child frame can call javascript on the parent frame using parent.foo()
, but that doesn't seem to work in IE8 or FF3.5. I found this SO question which explains how this security model works. But it seems odd that I can't do in Javascript what I can do with a simple <a>
tag. Is there any workaround to this at all? I know about window.postMessage, but (as far as I know) this only works in Firefox.
Example
server1/test.html
<html>
<head>
<script type="text/javascript">
function myCallback(foo) {
alert(foo);
}
</script>
</head>
<body>
<iframe src="http://server2/test2.htm" width="400" height="150"></iframe>
</body></html>
server2/test2.html
<html><body>
<script>
function clickit() {
parent.document.location = "http://www.google.com"; //not allowed
parent.myCallback("http://www.google.com"); //not allowed
}
</script>
<p>This should be in an iFrame!</p>
<p><a href="http://www.google.com" target="_parent">normal link (works)</a></p>
<p><a href="javascript:clickit()">javascript link</a></p>
</body></html>
OK I did more investigation, and it appears that postMessage works in all modern browsers, even IE (with the caveat that IE has a slightly different way of doing it). Here's how I got it to work (tested on WinXP in IE8, FF3.5, Chrome 3.0, Safari 4 beta, Opera 9.64):
server1/test.html
<html>
<head>
<script type="text/javascript">
if(navigator.appName == "Microsoft Internet Explorer")
window.attachEvent("onmessage", receiveMessage);
else
window.addEventListener("message", receiveMessage, false);
function receiveMessage(e) {
if(e.origin == "http://server2") //important for security
if(e.data.indexOf('redirect:') == 0)
document.location = e.data.substr(9);
}
</script>
</head>
<body>
<iframe src="http://server2/test2.htm" width="400" height="150"></iframe>
</body>
</html>
server2/test2.htm
<html><body>
<script>
function clickit() {
parent.postMessage('redirect:http://www.google.com', 'http://server1');
}
</script>
<p>This should be in an iFrame!</p>
<p><a href="http://www.google.com" target="_parent">normal link</a></p>
<p><a href="javascript:clickit()">javascript link</a></p>
</body></html>
A simple thing you can do is:
execute following from JavaScript code of iframe page
top.location = "https://www.google.co.in/";
this will change the location of window's URL to https://www.google.co.in/
.
One more thing -This strategy can also be useful when you do not want that any one can inframe your site
just write the above code in document ready part.
No, and for good reason. If you need this, then you must run all communication through one of the two servers; for example, have server1 act as as a proxy for all requests for "server2/test2.html".
If both parent and iframe are on subdomains under the same domain, you may be able to do something with the document.domain
property. If both body and iframe are treated as being from the same origin, changing the location should be possible; I haven't tried this myself. Some reading here
If the frames are on the same domain, you should be able to access the parent frame. Otherwise no, it's a security issue.
The only workaround that springs to mind would be to use AJAX to update a file on each of the servers, then check the contents of the opposite file server-side. You could do the same thing using a single database, if you allow connections from external domains.
This is all kind of overkill though, when you could simply pop-up a link in the frame and tell users to click it to continue.