14

I have a single page app with pagination and filters, and need to detect when the current URL changes at all. Is there not a simple way to add a listener to the current URL and trigger something when it changes? (No setting intervals either!)

  1. User lands on www.foobar.com
  2. User does something, url changes to www.foobar.com?filter=hello
  3. My function runs

I have tried both onhashchange, and tried unbeforeunload, and neither are relevant for this.

window.onbeforeunload = function(e) {
   alert ('url changed!');
};

window.onhashchange = function() { 
alert ('url changed!');  
}

Is there a way to add a listener to the URL, and trigger something anytime it changes at all? (again, single page app so no refresh)

user3390251
  • 317
  • 2
  • 5
  • 22
  • 1
    Possible duplicate of [How to detect URL change in JavaScript](https://stackoverflow.com/questions/6390341/how-to-detect-url-change-in-javascript) – klugjo Dec 21 '17 at 03:40
  • I looked at that - thats an "onhashchange" scenario. Mine is a bit different, no hashes, and i dont' want to set intervals. – user3390251 Dec 21 '17 at 03:43
  • @klugjo nope - as that has a has in the url. Here's just mere parameters. – Beni Sinca Apr 02 '20 at 13:09

2 Answers2

9

If you don't want to use setInterval, you can override the history.pushState event:

(function(history){
    const pushState = history.pushState;
    history.pushState = function(state) {
        if (typeof history.onpushstate == "function") {
            history.onpushstate({state: state});
        }
        // Call your custom function here
        return pushState.apply(history, arguments);
    }
})(window.history);
klugjo
  • 19,422
  • 8
  • 57
  • 75
  • this is getting close! although it gives me a console error of Uncaught TypeError: Failed to execute 'pushState' on 'History': 2 arguments required, but only 1 present. It might be conflicting with other code on the site... – user3390251 Dec 21 '17 at 04:09
  • why `History`, shouldt it be `history` ? no caps – klugjo Dec 21 '17 at 04:18
  • 2
    Arrow functions do not expose an `arguments` object, you would have to use `history.pushState = (state, ...args) => {` and `pushState.call(history, state, ...args);` –  Dec 21 '17 at 04:22
9

you can use MutationObserver to listen to URL changes amongst other things:

let previousUrl = '';
const observer = new MutationObserver(function(mutations) {
  if (window.location.href !== previousUrl) {
      previousUrl = window.location.href;
      console.log(`URL changed from ${previousUrl} to ${window.location.href}`);
    }
});
const config = {subtree: true, childList: true};

// start listening to changes
observer.observe(document, config);

// stop listening to changes
// observer.disconnect();
GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
  • By using `MutationObserver` like this, you are not listening to URL changes, you are listening to changes to the DOM and trying to catch changes to the url as a possible side effect. But it is entirely possible for the url to change without the DOM changing at all. – ArcadeRenegade Aug 19 '23 at 20:03