Deep linking into an iframe, cross-domain
Why would you want to do this? My use case was a gallery application where we needed to deep-link to a specific gallery entry. Alas, the gallery would be iframed. Yes, iframes should be avoided, but sometimes in real-life you have to just deal with it.
Imagine my surprise when I discovered that passing the parent window.location
object into an iframe across domains is not only possible, but is easy and works in most browsers, down to IE8.
The Solution
Use window.postMessage()
to pass messages to the iframed window.
Outer page
window.onload = function()
{
var child = document.getElementById('deep_link_frame');
var msg = {
"location" : {
"hash" : window.location.hash,
"host" : window.location.host,
"hostname" : window.location.hostname,
"href" : window.location.href,
"origin" : window.location.origin,
"pathname" : window.location.pathname,
"port" : window.location.port,
"protocol" : window.location.protocol,
"search" : window.location.search
}
};
child.contentWindow.postMessage(JSON.stringify(msg), '*');
};
Inner page
function bindEvent(el, eventName, eventHandler)
{
if (el.addEventListener)
{
el.addEventListener(eventName, eventHandler);
}
else
{
el.attachEvent('on' + eventName, eventHandler);
}
}
bindEvent(window, 'message', function(e)
{
if (e.origin === "http://your-domain.com")
{
var message = JSON.parse(e.data);
alert(message.location.href);
}
});
Limitations
There are a few land mines to watch out for if you need to support IE8 and IE9:
- All messages should be sent as strings to avoid a nasty bug in IE8-9. If you want to pass an object, pass it in JSON format.
- You can’t
JSON.serialize()
thewindow.location
object in IE8. If you are trying to pass that object, you have to copy the properties one by one. - IE only supports
el.contentWindow.postMessage()
, notel.postMessage()
.
Written on October 22, 2013