6

The documentation for the popstate Window event states:

Note that just calling history.pushState() or history.replaceState() won't trigger a popstate event. The popstate event will be 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).

I need a way to execute some code when the URL changes by means that don't trigger the popstate event (such as history.replaceState()). Preferably, using the MutationObserver API[1], and most definitely without polling the URL every x seconds.

Also, hashchange won't do, as I must act on every change in the URL, not just the hash part.

Is that possible?


[1] It is explained on another question why the MutationObserver API doesn't work for this.


(other) Related questions:

14
  • just call your other code when you call replaceState(), or create a custom event and dispatch it. if code you don't control calls it, wrap the function to achieve the last sentence. Commented Jun 25, 2019 at 19:26
  • But I'm not the one calling replaceState() and similar functions. The web application code is. (I'm writing an userscript). Commented Jun 25, 2019 at 19:27
  • can't you run the userscript before the other code loads? most extensions provide that as a setting. Commented Jun 25, 2019 at 19:28
  • You could continuously poll in an interval but you don't want that state running/consuming in the background the entire time? (just thinking) Commented Jun 25, 2019 at 19:29
  • @dandavis Yes, I'm currently doing that, but the script is only loaded once (when the page is first loaded). If the application changes its own URL, my script must detected it, and that's what I'm after. Commented Jun 25, 2019 at 19:30

1 Answer 1

9
+50

You need to redefine (wrap) the history.replaceState that the other script is using:

(function(){
  var rs = history.replaceState; 
  history.replaceState = function(){
    rs.apply(history, arguments); // preserve normal functionality
    console.log("navigating", arguments); // do something extra here; raise an event
  };
}());

No polling, no waste, no re-writing, no hassle.

Do the same for pushState, or whatever other natives (like ajax) you wish/need when writing userscripts.

Sign up to request clarification or add additional context in comments.

9 Comments

The OP would need to do the same with pushState, and something similar with location, location.href, etc.
@HereticMonkey: no, changing location.href would reload the page and destroy the script variable anyway (though the user script would still fire on the page load then, as usual). i mentioned pushState in the answer...
Yeah, I'm kind of surprised no one noted that in the question. I can also just type in the address bar...
I'll be back in a couple hours and test this; thanks for answering
np. it's not a pattern i would use in a lib on production code, because of remotely possible perf or compat issues, but for a user-script it's perfect. when JS doesn't provide what you want, sometimes you have to cheat...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.