As web page security has increased talking to your child web pages has gotten more difficult, but there is a simple way, and best of all it won’t throw security errors.
JavaScript comes with a PostMessage function that quickly allows parent pages to talk to children, and even more important for child pages to answer back.
As an example we will need two html pages containing some JavaScript, these will be masterpage.html and childpage.html. The source for this project is available here.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body onload="go()">
<input type="button" onclick="openwindow()" value="Open Child Window" />
<br />
<input type="button" onclick="closewithmessage()" value="Close Child Window"/>
<br />
<input type="button" onclick="displaymessage()" value="Display Message" />
<br />
<script type="text/javascript">
var myWindow = null;
function go() {
window.addEventListener('message', receiveMessage, false);
}
function makemessage(action, value) {
var obj = new Object();
obj.action = action;
obj.value = value;
return JSON.stringify(obj);
}
function receiveMessage(event) {
if (event.origin = "https://localhost:44323") {
if (event.data == "closed") {
myWindow = null;
}
}
}
function openwindow() {
if (myWindow == null) {
myWindow = window.open("childpage.html", "_blank");
}
}
function closewithmessage() {
if (myWindow != null) {
myWindow.postMessage(makemessage('close',''), 'https://localhost:44323');
}
}
function displaymessage() {
if (myWindow != null) {
myWindow.postMessage(makemessage('text','This is the message to display'), 'https://localhost:44323');
}
}
</script>
</body>
</html>
And for childpage.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body onload="go()">
<h2>Child Page</h2>
<br/>
<br/>
<input type="text" id="textField" value="" />
<script type="text/javascript">
function go() {
window.addEventListener('message', receiveMessage, false);
}
function receiveMessage(event) {
if (event) {
if (event.origin != "https://localhost:44323") return;
var dta = JSON.parse(event.data);
switch (dta.action) {
case 'close': {
event.source.postMessage("closed", "https://localhost:44323");
window.close();
break;
}
case 'text': {
var field = document.getElementById("textField");
if (field != null) field.value = dta.value;
}
}
}
}
</script>
</body>
</html>
They key to how this works is to create a listener event on the child page, and the master page if you want 2 way communication. This can be done in the onload event.
function go() {
window.addEventListener('message', receiveMessage, false);
}
The receiveMessage function takes a single parameter of the event.
function receiveMessage(event) {
if (event) {
if (event.origin != "https://localhost:44323") return;
}
}
The function needs to check if the event actually contains any information, and also for security the origin should be checked. If you don’t plan on receiving any cross page information then don’t create an event handler. It is possible to send messages with no origin attached but unless you can be sure your intranet is secure don’t do it.
Inside the event there is a property called event.data that contains the information passed. This can be a normal JavaScript variable or my preferred method is to pass JSON strings so that more than a single piece of information can be passed.
Sending data
Data is sent using the .postMessage function, this is done from the variable containing the window object, in the above text example it is the variable returned after the child window is opened.
function makemessage(action, value) {
var obj = new Object();
obj.action = action;
obj.value = value;
return JSON.stringify(obj);
}
function openwindow() {
if (myWindow == null) {
myWindow = window.open("childpage.html", "_blank");
}
}
function closewithmessage() {
if (myWindow != null) {
myWindow.postMessage(makemessage('close',''),'https://localhost:44323');
}
}
The function openWindow is called and it simply opens a child window, the child window contains the receiveMessage event handler and can receive information from the master window. The makemessage function simply creates a JSON string with two items in it, an ‘action’ value and a ‘value’ value. This allows the child event handler to deal with multiple message.
To close the child window we won’t use the window.close() functionality from the parent, we will send a JSON message like ‘action’:’close’,’value’:” to the child and the event handler that was attached with when the child page was opened will receive it and process it. This should also prevent any annoying ‘Do you want to close’ popup boxes, and it allows you the developer to keep the interface clean without leaving it to the user.
function receiveMessage(event) {
if (event) {
if (event.origin != "https://localhost:44323") return;
var dta = JSON.parse(event.data);
switch (dta.action) {
case 'close': {
event.source.postMessage("closed", "https://localhost:44323");
window.close();
break;
}
case 'text': {
var field = document.getElementById("textField");
if (field != null) field.value = dta.value;
}
}
}
}
The event handler decodes the JSON and contains a switch statement that handles each kind of message. As you can see there is a ‘text’ option that will transfer plain text to the child page, but if you look at the ‘close’ statement closer you can see it tries to pass a message back to the parent using the event.source.postMessage statement. The source property of the event property contains the handle of the source of the message so we can easily send one back without having to use a call like this.parent.
function go() {
window.addEventListener('message', receiveMessage, false);
}
function receiveMessage(event) {
if (event.origin = "https://localhost:44323") {
if (event.data == "closed") {
myWindow = null;
}
}
}
And in the master page we created an event listener to handle the returned message and clear the window variable after the child window has closed. This ensures that the global variable used to store the child window handle is available for reuse even though the child window closed itself.
This is such a simple and effective method to pass information between web pages without worrying about cross page scripting errors or issues when you deploy to production systems.