How to get Firefox to fire the popstate event when going back from a page on a different domain?
Asked Answered
T

4

7

I have a simple web page, namely:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>History hacks</title>
<script>
window.onpopstate = function (e) {
    alert("location: " + document.location + ", state: " + JSON.stringify(e.state));
}
window.onload = function (e) {
    alert('page loaded');
}
</script>
</head>
<body>
<p> <a href="http://www.yahoo.com">Yahoo</a> <a href="#part1">Part 1</a></p>
</body>
</html>

Now there are a number of differences regarding how Chrome and Firefox trigger the popstate event (I shudder to think what I'm up against when I get around to testing IE), but one that's giving me problems here is that Chrome will trigger a popstate event whenever I click on either of those two links, and then again when I hit the back button. Firefox will trigger the event for the link that changes the hash part (only the first time though if the hash link is the same), and won't trigger it at all if I click on the Yahoo link and then click the back button.

So is there a way that I can tell in Firefox that a user has just clicked back and landed back on my page from a completely different site on a different domain? Is there another event that would work for this purpose in Firefox? (The load event does not get triggered either when I go back from yahoo.com.)

Tullis answered 11/10, 2012 at 13:18 Comment(0)
H
12

To get a popstate event when the back (or forward) button is used to go to the initial page load, use replaceState() like

window.onload = function(e) {
  history.replaceState(null, null, document.URL);
}

To ignore the initial popstate that Chrome generates when the page is loaded you can tag the state whenever you call pushState / replaceState, e.g.

history.pushState({myTag: true}, null, url);

Then your popstate handler just filters for myTag

window.onpopstate = function(e) { 
  if (!e.state.myTag) return; // none of my business
  // code to handle popstate 
}

You can combine these two for a trivial cross-browser solution:

window.onpopstate = function(e) { 
  if (!e.state.myTag) return; // none of my business
  // code to handle popstate 
}

window.onload = function(e) {
  history.replaceState({myTag: true}, null, document.URL);
}

@Boris Zbarsky has detailed the bfcache. I haven't thought about how to combine that with my approach. I just disable it by adding a page unload handler

window.onunload = function(e) { }
Hubey answered 12/10, 2012 at 21:14 Comment(4)
This is a great answer for explaining how to make the history API work the same cross platform, but it doesn't actually answer OP's question: how to tell if the user actually clicked "back" to end up on the page. Using your example, you can tell that the user clicked back in Chrome and Safari because mytag will not be null in the onpopstate handler. However in firefox, onpopstate is not called so there seems to be no way to determine if the user is returning to the page or if it is a first time visit. So is there actually any way to distinguish this in Firefox?Ignacia
@Karma: if you disable the bfcache (see the last part of my answer) then Firefox should behave similarly to Chrome. But read Boris Zbarsky's answer for a nice illustration of why you should prefer Firefox's page cache to Chrome's behavior.Hubey
Thanks @Sean Hogan. After a re-read on Firefox bfCaching, I realized it doesn't work on my site because we use https. Firefox always refreshes the page. I guess there's nothing I can do about that.Ignacia
@Karma: I didn't know about https. Thanks for the tip.Hubey
B
2

You're presumably looking for the pageshow event if you want to be notified when your page is shown when going back even if it got cached in the page cache.

Note that if there is no load event that also means the page still has exactly the same DOM and script execution environment it did when it was navigated away from. Basically it's as if the user switched tabs for a while, as opposed to navigating.

So given that, do you still want to get an event in that situation? Do you get events you look for when the user switches back to the tab with your page in it?

Bettis answered 11/10, 2012 at 19:37 Comment(0)
W
0

before unload I reload my page (to get initial status) then set new href

window.onunload = function(e) {
  location.reload();
  location.href = **new_url** ;
}

I have to do that because firefox saves last state of my page and restores it instead of recreate it.

Wheedle answered 14/10, 2014 at 8:58 Comment(0)
L
0

I had the same question and had to dig into spec to figure out why popstate event doesn't fire in any browser when back button is used to return from a page on different domain. It turns out that popstate should not fire in this case as document's state changed is not true and popstate should only fire if state changed is true. For state changed to be set to true spec says:

Let state changed be true if the Document of the specified entry has a latest entry, and that entry is not the specified entry; otherwise let it be false.

My understanding is that when we return to our page from a page in different domain our page has no latest entry since document has changed and new document has no latest entry yet. Again from spec:

Each Document in a browsing context can also have a latest entry. This is the entry for that Document to which the browsing context's session history was most recently traversed. When a Document is created, it initially has no latest entry.

However there is still a way to see if user has come back to your page by setting a flag in history.state in your page using history's pushState or replaceState methods and checking for existence of this flag in history.state on page load.

For more read in WHATWG's HTML spec the part dealing with popstate event: https://html.spec.whatwg.org/multipage/browsers.html#history-traversal

Lightsome answered 7/11, 2015 at 11:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.