28

Why

window.addEventListener('popstate', () => alert('pop'));

window.history.pushState(null, '', '/foo');

does not alert pop ?

NB: Testing on latest chrome

--

According to MDN:

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 pushState or affected by a call to replaceState, the popstate event's state property contains a copy of the history entry's state object.

So why my pushState does not trigger the popstate event?

abernier
  • 27,030
  • 20
  • 83
  • 114

6 Answers6

64

You can manually trigger popstate event on window every time you call history.pushState().

history.pushState(state, '', url);

var popStateEvent = new PopStateEvent('popstate', { state: state });
dispatchEvent(popStateEvent);
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
sgtpep
  • 819
  • 1
  • 7
  • 3
16

The paragraph you reference is a little ambiguous. Reading the example on the same page, it is clear that popstate is only triggered when the user clicks the back button, not when the script calls pushState().

Sean Hogan
  • 2,902
  • 24
  • 22
  • 10
    popstate is also triggered when the user presses the forward button. – circuitry Jan 12 '14 at 00:49
  • pushstate does trigger popstate! Hence "A popstate event is dispatched to the window every time the active history entry changes"! – Alex Gill Sep 07 '16 at 13:46
  • 1
    @AlexGill Do you have a test-case that demonstrates this behavior? Something like: ` window.onpopstate = function(e) { alert('popstate'); } history.pushState(null, ''); ` – Sean Hogan Sep 08 '16 at 02:22
  • popstate is *also* triggered with `window.location.hash = ""`. Dmitri Farkov's answer below mentions this detail and it's important I think. – Goodword Feb 11 '20 at 20:40
13

You are reading MDN's "guide page" which is not meant to be normative.

Consider reading MDN's "documentation page" for WindowEventHandlers.onpopstate instead:

Note that just calling history.pushState() or history.replaceState() won't trigger a popstate event. The popstate event is only triggered by doing a browser action such as a clicking on the back button (or calling history.back() in JavaScript). And the event is only triggered when the user navigates between two history entries for the same document.

Another undocumented way of triggering popstate is by direct manipulation of the window.location object.

// this also triggers popstate 
window.location.hash = "#some-new-hash"
Dmitri Farkov
  • 9,133
  • 1
  • 29
  • 45
Pacerier
  • 86,231
  • 106
  • 366
  • 634
2

My solution:

var url = "http://awesome.website.net/route/to/paradise";
window.history.pushState({}, "", url);
window.history.pushState({}, "", url); // yes twice
window.history.back();

It will trigger a soft-navigation via 'popstate' event and no HTTP request.

  • Is this what all of the front-end frameworks do, too? – elliottregan Sep 15 '15 at 23:49
  • 1
    That sucks, because you end up with redundant forward state. No, frameworks don't do that. They just have good code that calls the same callback on both `popstate` and after `pushState`. – Robo Robok May 02 '16 at 08:23
0

Document https://developer.mozilla.org/en-US/docs/Web/Events/popstate says:

Note that just calling history.pushState() or history.replaceState() won't trigger a popstate event. The popstate event will been triggered by doing a browser action such as a click on the back or forward button (or calling history.back() or history.forward() in JavaScript).

Pang
  • 9,564
  • 146
  • 81
  • 122
zhuxy
  • 140
  • 1
  • 5
-1

I ran into this too... I think the event only fires if you have something at the top level of your data object that is distinct from the previous state.

Try this:

var data = {rand: Math.random()};
window.history.pushState(data, '', '/foo');
Baz
  • 36,440
  • 11
  • 68
  • 94
JeKo
  • 59
  • 2