I'm playing with window.onpopstate, and there is a thing that annoys me:
Browsers tend to handle the popstate event differently on page load.
Chrome and Safari always emit a popstate event on page load, but
Firefox doesn't.
source
I tested it, and yeah, in Chrome and Safari 5.1+ the popstate event is fired on page load, but not in Firefox or IE10.
The problem is, that I want to listen only to popstate events where user clicked the back or forward button (or the history was changed via javascript), but don't want to do anything on pageload.
In other words, I want to differentiate the popstate event from page load from the other popstate events.
This is what I tried so far (I'm using jQuery):
$(function() {
console.log('document ready');
setTimeout(function() {
window.onpopstate = function(event) {
// Do something here
}, 10);
});
Basically I'm try to bind my listener function to popstate late enough to be not bound on page load, only later.
This seems to work; however, I don't like this solution. How can I be sure that the timeout chosen for setTimeout is big enough, but not too big (because I don't want it to wait too much).
I hope for a smarter solution!
Check for boolean truth of event.state in popstate event handler:
window.addEventListener('popstate', function(event) {
if (event.state) {
alert('!');
}
}, false);
To ensure this will work, always specify a non-null state argument when calling history.pushState() or history.replaceState(). Also, consider using a wrapper library like History.js that provides consistent behavior across browsers.
I had a similar problem and i had to validate to make sure if page was loaded completely.
I used something like this :
var page_loaded = false;
window.onpopstate = function(event){
if(!page_loaded){
page_loaded = true;
return false;
}
//Continue With Your Code
}
To react on popstate event, you need to push some state onto the session history.
For example add this line to the document ready section:
history.pushState(null, null, window.location.pathname);
Not ideal, but it works in Chrome, Firefox and other browsers as well.
Then the event is fired correctly when user clicks on Back or Forward button, also when history.back(), history.forward(), history.go() methods are called manually. Each time when popstate has been invoked, you have to push another state again to make it working.
See also:
Single-Page Apps and HTML5 pushState
How to Detect Browser Back Button event - Cross Browser
It seems none of the browsers are emitting the event on page load any more as of today:
Browsers used to handle the popstate event differently on page load, but now they behave the same. Firefox never emitted a popstate event on page load. Chrome did until version 34, while Safari did until version 10.0.
Source: https://developer.mozilla.org/en-US/docs/Web/API/PopStateEvent
Related
Upon clicking the back button in the browser, I would like to prevent the default behaviour of going one page back and instead do an action. I'm using the "popstate" event listener. The following function (I'm using Vue 2) works in all major browsers and even in Firefox for Android, but when I test it in Chrome for Android, it simply goes back one page without popstate being triggered at all.
mounted() {
history.pushState(null, null, <current-url>);
window.addEventListener("popstate", () => { alert(1) });
}
I tried wrapping the popstate event inside the load event and giving it a timeOut of 0, but it still didn't work specifically in Chrome for Android. The version I'm testing on is 93.
I did some more research and it seems that Chrome won't let you use popstate if there is no user interaction first. As long as you click on something or scroll down on mobile, popsate will work, otherwise it won't. I tried to simulate user interaction with click(), but that didn't work either. It seems Chrome wants genuine user interaction. I also realized this is sort of a duplicate of: Chrome popstate not firing on Back Button if no user interaction
My popstate event handler is defined thusly:
window.addEventListener('popstate', function (ev) {
alert('popstate');
/* recompose dom */
});
It works fine while I am within my site as I use back and forward, however when I navigate to another site and then come back my event does not fire.
I assume this is by design based on the following comment on Mozilla Developer:
Browsers tend to handle the popstate event differently on page load.
Chrome (prior to v34) and Safari (prior to 10.0) always emit a
popstate event on page load, but Firefox doesn't.
If this is the case, how do I get the most recent pushed state when coming back to my page from another site.
I figured it out; pull the current page state from history.state on document ready and apply it.
I tried onbeforeunload event but it's not working when leaving the page it's only working when I reload but every thing works fine on edge.
I think Chrome have changed somethings in configuration.
Is there a way to fix that or another method?
onbeforeunload = function(){
return("bye");
}
AND is there a way I can check if user is closing the page or redirecting to another url with out firing on reloading or can I not do that?
Even when using JQuery, a framework with the objective cross browser compatibility, they say:
The exact handling of the unload event has varied from version to version of browsers. For example, some versions of Firefox trigger the event when a link is followed, but not when the window is closed. In practical usage, behavior should be tested on all supported browsers and contrasted with the similar beforeunload event.
Source
So you have to accept an inconsistent behaviour.
You could try doing this:
window.onbeforeunload = function(e) {
return "Bye";
}
As you need to attach the event to the window
I'm trying to create a Chrome plugin for facebook and I'm using onpopstate event to check when the user goes to another page. The only problem is that the onpopstate doesn't fire.
This is the (simple) code I'm using:
window.onpopstate = function() { console.log('pop'); };
this is a screen of the problem:
As you can see the pushState code is called, but the onpopstate listener is not.
Do you know what's happening here?
#enhzflep's answer is in the comments above and not immediately obvious. From MDN:
Calling history.pushState() or history.replaceState() won't trigger a popstate event. The popstate event is only triggered by performing a browser action, such as clicking on the back button (or calling history.back() in JavaScript), when navigating between two history entries for the same document.
In other words, the onpopstate event shouldn't be firing in this case.
I put all of my code in $(document).ready as per norm, but should I put my 'popstate' listener at the very end of this code too? Or does it matter?
This doesn't really matter, and since it's an event, can even be done before your ready method. The only thing needing to be placed inside document ready is code interacting with the DOM. Everything else doesn't (and possibly shouldn't) be placed in document ready.
Example:
window.onpopstate = function() {
// binding this event can be done anywhere,
// but shouldn't be inside document ready
};
$(document).ready(function() {
// DOM manipulation and other stuff
});
Now when popstate actually is triggered is a lot different than when it is bound. According to the Mozilla doc:
A popstate event is dispatched to the window every time the active history entry changes. If the history entry being activated was created by a call to history.pushState() or was affected by a call to history.replaceState(), the popstate event's state property contains a copy of the history entry's state object.
I was confused, because popstate was firing on every page load (I use chrome).
From https://developer.mozilla.org/en-US/docs/DOM/window.onpopstate:
Browsers tend to handle the popstate event differently on page load.
Chrome and Safari always emit a popstate event on page load, but
Firefox doesn't.
So in chrome (and apparently safari), the jquery ready method will execute, followed by the popstate event.
i.e. it doesn't matter if you attach the event within ready (or body.onload for that matter), the popstate event will happen after your ready method is complete.
In firefox (16.0.1) the popstate event does not fire on page loads (I can't test IE 10).
https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate
Calling history.pushState() or history.replaceState() won't trigger a popstate event. The popstate event is only triggered by performing a browser action, such as clicking on the back button (or calling history.back() in JavaScript), when navigating between two history entries for the same document.
Just add a key to the state every time you push to history or replacing the state, and check for it on the popstate event, if you don't use the state at all you can simply push {} as state and quit the pop state in case the event.state is null.