I have an HTML5 offline app (i.e. there's no server-side component/code).
It basically has two windows (parent and child). However, in some instances I need to programmatically refresh the parent window. When this happens, it loses its reference to the child, and the child's reference to window.opener is no longer valid. So my thinking was that I'd serialize the child window and store that in localStorage. Then when the parent refreshed it could pick up the window reference from localStorage and still interact with the child.
The problem is that this doesn't work (as per my previous question here Stringify DOMWindow object). I can't serialize a DOM window like any other object.
So how can I have my newly refreshed window pick up a reference to its predecessor's child?
Edit: Stressed the fact that it's an offline app. There's no server-side component.
I should also add that the reason I need to refresh the parent is to check for application updates (changes in the cache manifest). Since the parent is the first page in the application that loads, it basically manages the caching (in fact as an aside, in Safari if this window is closed during any of the caching process the entire browser crashes). So "parent" is essentially "first page that the user loads". This means that I can't have the "parent" in a frame, as the topmost window would then manage the caching, and require the refresh in order to look for updates. Actually, it appears that I can use the frame method, as refreshing any of the pages in the application will trigger the update check. Cumbersome though.
Set a flag once child window is open and unset it once its closed. In ShowPopup use event. preventdefault() if child window is open!
If you store a reference to the child window when you call window. open() , then you can poll using setInterval() to see whether the window is still open using the window.
From a child window or a small window once opened, we can transfer any user entered value to main or parent window by using JavaScript. You can see the demo of this here. Here the parent window is known as opener. So the value we enter in a child window we can pass to main by using opener.
Inside the SetName JavaScript function, the reference of the parent window txtName TextBox is obtained from window. opener instance using document. getElementById method of JavaScript. Finally, the DropDownList selected value is set into the TextBox value property.
I achieved this scenario using Window.postMessage, which enables cross-origin communication between Window objects. It supports: https://caniuse.com/#feat=mdn-api_window_postmessage
Basic working example for establishing communication between parent and child Window objects
In the parent app,
var childWindow = window.open(CHILD_URL);
setTimeout(() => { // postMessage on some browsers may need setTimout
childWindow.postMessage( // STEP 1
"INITIATE_CONNECTION", // message
CHILD_URL // targetOrigin
);
}, 500)
function receiveMessageFromChild(event) {
if (event.origin === CHILD_URL) { // we should always check with the event.origin
if (event.source) {
if (event.data === "CONNECTION_SUCCESSFUL") {
setTimeout(() => {
event.source.postMessage( // STEP 3 and STEP 7
"SEND_SOME_DATA_TO_CHILD",
CHILD_URL);
}, 500);
}
// other messages handling from child
}
}
}
if (window.addEventListener) {
window.addEventListener("message", receiveMessageFromChild, false);
} else if (window.attachEvent) { // for IE
window.attachEvent("onmessage", receiveMessageFromChild);
}
In the child app,
function receiveMessageFromParent(event) {
if (event.origin === PARENT_URL) { // we should always check with the event.origin
var parentWindow = window.opener || event.source;
if (parentWindow) {
if (event.data === "INITIATE_CONNECTION" || event.data === "RE_NITIATE_CONNECTION") { // "RE_NITIATE_CONNECTION" msg from parent when parent is refreshed
setTimeout(() => {
parentWindow.postMessage( // STEP 2
"CONNECTION_SUCCESSFUL",
PARENT_URL);
}, 500);
}
// other messages handling from parent
}
}
}
if (window.addEventListener) {
window.addEventListener("message", receiveMessageFromParent, false);
} else if (window.attachEvent) { // for IE
window.attachEvent("onmessage", receiveMessageFromParent);
}
To handle parent window refresh and retrieve child window reference after the parent refresh make the following changes in the above codes,
In the parent app,
document.body.onunload = () => { // before refreshing parent, this function will be called
if (childWindow) {
setTimeout(() => {
childWindow.postMessage( // STEP 4
"PARENT_REFRESHING",
CHILD_URL
);
}, 500);
}
};
function receiveMessageFromChild(event) {
// ... above mentioned code in the parent app for this function
.
.
.
// other messages handling from child
if (event.data === "PARENT_REFRESHED") {
setTimeout(() => {
event.source.postMessage( // STEP 6 - this event.source is a child window reference
"RE_NITIATE_CONNECTION",
CHILD_URL
);
}, 500);
}
}
In the child app,
function receiveMessageFromParent(event) {
// ... above mentioned code in the child app for this function
.
.
.
// other messages handling from parent
if (event.data === "PARENT_REFRESHING") {
setTimeout(() => {
event.source.postMessage( // STEP 5
"PARENT_REFRESHED",
CHILD_URL
);
}, 500);
}
}
In the above example, please refer to the STEPs from 1 to 7. STEP 6 is the child window reference when the parent is refreshed.
You can obtain the reference of child window simply by following trick.
newWin = window.open("", "child_window_name", "width=...");
if (newWin.location.href === "about:blank") {
newWin = window.open("a.html", "child_window_name", "width=...");
} else {
// We've already obtained the reference.
// However, IE and FireFox won't put focus on an already opened window.
// So we have to do that explicitly:
newWin.focus();
}
Note you must have a fixed child window name to make this trick works.
Example URL: http://josephj.com/lab/2011/window-open-reconnect/demo.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With