What I want to do:
opening an popup and send the postMessage when the popup is ready.
Problem:
I ran into Race Condition which the popup is not ready but the message is sent. I tried to listen to the "INIT" message and in the popup send back message. But the problem is when network latency or some slow computer will not receive the initial message.
The setTimeout obviously not a good solution
Code I have problem with:
Parent Window
const windowFeatures = "height=800,width=1280,toolbar=1,menubar=1,location=1";
const printWindow = window.open("/print", "Print_Me", windowFeatures);
setTimeout(() => {printWindow.postMessage({printPageStatus: "INIT"}, window.origin)}, 1000)
window.addEventListener("message", (event) => {
if(event.origin !== window.origin) return;
if(event.data.printPageStatus === "READY") {
printWindow.postMessage({message: "from parent", window.origin);
return;
}
});
The popup window
constructor() {
window.addEventListener("message", event => {
if(event.origin !== window.origin) return;
if(event.data.printPageStatus === "INIT")
this.sendReadyConfirmation(event);
if(event.data.message === "from parent") {
this.processMessages(event.data);
}
}, false);
}
sendReadyConfirmation(e): void {
e.source.postMessage({printPageStatus: "READY"}, e.origin);
}
Thank you
What you need to do is send the message when the window has loaded successfully :
const printWindow = window.open("/print", "Print_Me", windowFeatures);
printWindow.onload = () => {
printWindow.postMessage({printPageStatus: "INIT"}, window.origin)
};
Related
First of all I know this question has been asked already in differently ways but I've combed through all the questions on stackoverflow and tried their examples but nothing is working for me.
I can not receive a message from the popup even though when I try to check for opener it exist on the popup window. The parent window where I am receiving the message from the popup does not receive anything. It ignores receiveMessage.
Parent Window
openSignInWindow = (url: any, name: any) => {
let _url = this.baseUrl + `user/account/login/${url}`;
// remove any existing event listeners
window.removeEventListener('message', this.receiveMessage);
// window features
const strWindowFeatures = 'toolbar=no, menubar=no, width=600, height=700, top=100, left=100';
if (this.windowObjectReference === null || this.windowObjectReference.closed) {
/* if the pointer to the window object in memory does not exist
or if such pointer exists but the window was closed */
this.windowObjectReference = window.open(_url, name, strWindowFeatures);
window.focus();
} else if (this.previousUrl !== _url) {
/* if the resource to load is different,
then we load it in the already opened secondary window and then
we bring such window back on top/in front of its parent window. */
this.windowObjectReference = window.open(_url, name, strWindowFeatures);
this.windowObjectReference.focus();
} else {
/* else the window reference must exist and the window
is not closed; therefore, we can bring it back on top of any other
window with the focus() method. There would be no need to re-create
the window or to reload the referenced resource. */
this.windowObjectReference.focus();
}
// add the listener for receiving a message from the popup
addEventListener('message', event => this.receiveMessage(event), false);
// assign the previous URL
console.log('Listener Called', _url);
this.previousUrl = _url;
};
receiveMessage(event) {
this.cd.detectChanges();
alert('HELLO');
console.log('Receiver called')
// Do we trust the sender of this message? (might be
// different from what we originally opened, for example).
if (event.origin !== window.location.origin) {
return;
}
const { data } = event
// console.log(data)
// console.log(data.source === 'internal-redirect')
if (data.source === 'internal-redirect') {
sessionStorage.setItem('access_token', data['access_token']);
sessionStorage.setItem('fullname', data['fullname'])
this.authService.logged_in_user = data['fullname'];
this.username.emit(true);
const redirectUrl = '/';
window.location.pathname = redirectUrl;
}
};
Popup page
const params = window.location.search;
if (window.opener) {
// send them to the opening window
window.opener.postMessage(params);
// close the popup
window.close();
}
service worker file:
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed.
);
// Execute callback
registration.postMessage({action: 'skipWaiting'})
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
}`
self.addEventListener('message', function(event) {
if (event.data.action === 'skipWaiting') {
self.skipWaiting();
}
});
//listening in app.js controller change event
// reload once when the new Service Worker starts activating
var refreshing;
navigator.serviceWorker.addEventListener('controllerchange',
function() {
if (refreshing) return;
refreshing = true;
window.location.reload();
}
);
what it actually does:
If it finds any update, sending a postMessage as skipWating
2.Once the message recieved by listener , it calls the skipWaiting()
3.then controllerchange event gets called where we refreshing the page.
Why it gets into infinite loop of reload()
Your first bit of code, everything under registration.onupdatefound, shouldn't be in the service worker file. It should be in your web app's window context.
The bit that should be in your service worker file is:
self.addEventListener('message', function(event) {
if (event.data.action === 'skipWaiting') {
self.skipWaiting();
}
}
There's documentation for another "recipe" that accomplishes this at https://developers.google.com/web/tools/workbox/guides/advanced-recipes#offer_a_page_reload_for_users. It uses the workbox-window library to simplify things a bit.
I want to disconnect all my users when the tab is closing or the browser is getting closed, so far so good. But when I refresh the page, all my users get disconnected too, this should not happen on refresh. Is it possible to avoid to execute this event on refresh? I saw some users doing with localStorage, but I still didn't get the point.
componentDidMount() {
this.beforeUnloadListener();
}
beforeUnloadListener = () => {
window.addEventListener("beforeunload", (ev) => {
ev.preventDefault();
// code to logout user
});
};
The way beforeunload works, you can not differentiate weather it's a page refresh or a browser close. beforeunload it is a quite confusing event avoid using this.
Hence for cases where you are dealing with the session you should use session storage. The sessionStorage object stores data for only one session (the data is deleted when the browser tab is closed).
Have done this on react application and its work for me on index.html file write this in script tag.
<script type="text/javascript">
window.addEventListener("beforeunload", (event) => {
window.localStorage.isMySessionActive = "true";
});
window.onunload = function (e) {
const newTabCount = localStorage.getItem("tabsOpen");
if (newTabCount !== null) {
localStorage.setItem("tabsOpen", newTabCount - 1);
}
};
</script>
Then go on main file and write this code.
useEffect(() => {
// define increment counter part
const tabsOpen = localStorage.getItem("tabsOpen");
if (tabsOpen == null) {
localStorage.setItem("tabsOpen", 1);
} else {
localStorage.setItem("tabsOpen", parseInt(tabsOpen) + parseInt(1));
}
// define decrement counter part
window.onunload = function (e) {
const newTabCount = localStorage.getItem("tabsOpen");
if (newTabCount !== null) {
localStorage.setItem("tabsOpen", newTabCount - 1);
}
};
if (performance.navigation.type == performance.navigation.TYPE_RELOAD) {
window.localStorage.isMySessionActive = "false";
} else {
const newTabCount2 = localStorage.getItem("tabsOpen");
let value = localStorage.getItem("isMySessionActive");
if (value == "true") {
if (newTabCount2 - 1 == 0) {
localStorage.clear();
window.localStorage.isMySessionActive = "false";
} else {
window.localStorage.isMySessionActive = "false";
}
}
}
}, []);
I am setting up nodejs/socket.io private messaging between two users. Everything is working as desired but the only problem is to show read receipts of the messages.
As I understand, the only way how to do this is to detect if the message has appeared on the screen of the recipient. So, I want to emit a socket.io event when message appears on the screen of the recipient:
socket.emit('messages read', user);
All together:
var newmessages = 0;
socket.emit("chat message", data); //sending message
newmessages = 1;
function onVisibilityChange(callback) {
var visible = true;
if (!callback) {
throw new Error('no callback given');
}
function focused() {
if (!visible) {
callback(visible = true);
}
}
function unfocused() {
if (visible) {
callback(visible = false);
}
}
if ('hidden' in document) {
document.addEventListener('visibilitychange',
function() {(document.hidden ? unfocused : focused)()});
}
if ('mozHidden' in document) {
document.addEventListener('mozvisibilitychange',
function() {(document.mozHidden ? unfocused : focused)()});
}
if ('webkitHidden' in document) {
document.addEventListener('webkitvisibilitychange',
function() {(document.webkitHidden ? unfocused : focused)()});
}
if ('msHidden' in document) {
document.addEventListener('msvisibilitychange',
function() {(document.msHidden ? unfocused : focused)()});
}
if ('onfocusin' in document) {
document.onfocusin = focused;
document.onfocusout = unfocused;
}
window.onpageshow = window.onfocus = focused;
window.onpagehide = window.onblur = unfocused;
};
onVisibilityChange(function(visible) {
if (visible == true) { //here I want to send read confirmation when message appears on the screen
if (newmes != '0') {
socket.emit('messages read', user);
newmessages = 0;
}
}
});
The problem
It works but I don't know how to set the initial state of the visible window. For example, user A is chatting with user B and both users have chat windows opened. The will never get read receipts if continue chatting without switching browser tabs or minimizing the browser that will change the visibility. How can I set visible to true when users first time load page with chat?
You can use window.onload to do that. The load event is fired when the page loads, so you can set your initial state in this event handler.
var visible;
window.onload = function() {
// Set your initial state.
visible = true;
};
I'm writing a chat webapp that needs to be able to trigger desktop push notifications through the notifications API: https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API
Unfortunately, it seems that the notifications don't show up until I flush it all out by making another notification with this fiddle: https://jsfiddle.net/yoshi6jp/Umc9A/
This is the code that I am using:
function triggerDesktopNotification() {
function makeNotification() {
var notification = new Notification('AppName', {
body: 'You have a new message!',
icon: '/favicon.ico',
});
notification.onclick = () => {
notification.close();
};
}
if (Notification.permission === 'granted') {
makeNotification();
}
else if (Notification.permission !== 'denied') {
Notification.requestPermission(function (permission) {
if (permission === 'granted') {
makeNotification();
}
});
}
}
I can confirm that the code is executing properly by placing console.log() immediately after the new Notification call. Interestingly, if I put an alert() there instead, the notification shows up when I see the alert box (after navigating back into my tab).
If I understood you right ;
Alert interrupts program stack where it placed i think.Why dont you try to fire it async with setTimeout function like that ?
setTimeout( function(){
alert("asd");
})
edited js fiddle here