- target page is loaded using an hidden iframe
- once iframe finishes loading, send data over via postMessage
- register a function to wait for and respond to message to be received from target page only once
- async operation has been wrapped with a jQuery promise
//Utility routine to generate a unique id
function createGuid()
{
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
var deferred = $.Deferred();
var iframeID = createGuid();
var iframe = $("<iframe></iframe>", {
"src": targetUrl,
"id": iframeID,
"style": "display:none;"
});
$("body").append(iframe);
iframe.one("load", function(){
var childFrame = $("#"+iframeID)[0];
childFrame.contentWindow.postMessage(JSON.stringify(dataToSend), targetOrigin);
});
$(window).on("message", handleMessage);
function handleMessage(event){
$(window).off("message", handleMessage);
var dataReceived = JSON.parse(event.originalEvent.data);
$("#"+iframeID).remove();
deferred.resolve(dataReceived);
}
return deferred.promise();
}
Usage example:
$("#btnTest").click(function(){
var dataSend = {"value": 123};
sendAndReceiveMessage("child.html", "*", dataSend).done(function(data){
alert("Test result: " +data.value);
});
});
var dataSend = {"value": 123};
sendAndReceiveMessage("child.html", "*", dataSend).done(function(data){
alert("Test result: " +data.value);
});
});
A sample implementation of child.html is below. In this case I just double the value received from calling page and return it back.
(function(){
function receiveMessage(event){
var data = JSON.parse(event.data);
data.value *= 2;
event.source.postMessage(JSON.stringify(data), "*");
}
$(document).ready(function(){
window.addEventListener("message", receiveMessage, false);
});
})();