Internet Explorer 6 & 7 document.domain bug
I've been coding some javascript ajax code that inserts an iframe, and into the created iframe, inserts a form and submits the form to a (cross domain) server. This is an old cross-domain ajax technique by now, but while implementing it I came across this ridiculously annoying bug in IE. The line in red below will result in an "Access Denied" exception being thrown...again, only in IE. Tried this with IE6 under WinXP Media Center Edition SP2, IE7 under WinXP Home Edition SP2, and IE7 Windows Vista Home. Needless to say...it works just fine in FireFox.
This page should be served off of http://waelchatila.com. As you can see, the document.domain is explicitly set to the domain the page was served from. The iframe src is also from the same server. I've tried it with a whole variety of variations, none of the demonstrated here but tested for.
- iframe's document.domain = 'waelchatila.com';
- iframe src is empty
- iframe src is "javascript:false"
Now, if the document.domain = 'waelchatila.com'; line is removed, it works. In order for this to work, you'll need to reload this page if you clicked the previous button since document.domain has now already been assigned.
The same results present itself if the iframe is created with document.createElement('iframe') and document.appendChild(...)
I've yet to find a workaround for this issue. I'll be positing another entry if I found out how. Please let me know if you know of one!
del.icio.us
technorati
[more]
Re: Internet Explorer 6 & 7 document.domain bug
Re: Internet Explorer 6 & 7 document.domain bug
Re: Internet Explorer 6 & 7 document.domain bug
<script>
document.domain = 'adp.com';
var iframe = document.createElement("iframe");
iframe.src = 'http://test.adp.com/newIframe.html';
document.body.appendChild(iframe);
var timer = setInterval(resumeCode, 100);
function resumeCode()
{
if(iframe.contentWindow.okToResumeParent) {
clearInterval(timer);
alert("iframe document body content is: " + iframe.contentWindow.document.body.innerHTML);
}
}
</script>
And here's the HTML inside the iframe:
<html>
<head>
<script>
document.domain='adp.com';
var okToResumeParent = true;
</script>
</head>
<html>
<body>
This is the body content of the new iframe.
</body>
</html>
Re: Internet Explorer 6 & 7 document.domain bug
As mentioned above, this is a race conditions. While the iframe is being created and loaded, the document.domain is not explicitly set, so any parent document that does have it explicitly set will not be able to communicate with it immediately.
The workaround I use the most often is to point the iframe (or frame, or window) src to a "blank" html page that includes the setting of the document.domain value, plus a callback call to top.parent.loadContent() where the parent (whoever created the iframe) has dfined loadContent() and that function reaches into the iframe to access or overwrite it with whatever it wants.
The other workaround is a variation on that mentioned above, to create a setInterval loop that keeps checking to see if the frame is loaded. There is a cross browser hack that'll let you detect if the iframe/frame/window is loaded without reaching into it that looks like this.
document.domain = "my.domain"; // this is where the problem starts in IE
var iframe_loaded = false;
function createIframe() {
var myframe = ... create iframe object here
myframe.src = "URL to empty html page with document.domain set properly";
// We have to detect when the empty frame content has loaded
// Following 5 lines are cross browser compatible.
if (myframe.attachEvent) {
myframe.attachEvent("onload", function() {iframeFinish()});
} else {
myframe.onload = function() {iframeFinish()};
}
}
// New method added to HTMLEditor class to set iframe_loaded state
function iframeFinish() {
iframe_loaded = true;
}
Now after you call createIframe() start a setInterval loop that looks for iframe_loaded to be true, before proceeding to the next step that needs to reach into the iframe for some value, or to change its contents.
If you change the iframe's contents, be sure to set the document.domain *every* time or you'll lose contact with it again.