Event when window.location.href changes

237,472

Solution 1

popstate event:

The popstate event is fired when the active history entry changes. [...] The popstate event is only triggered by doing a browser action such as a click on the back button (or calling history.back() in JavaScript)

So, listening to popstate event and sending a popstate event when using history.pushState() should be enough to take action on href change:

window.addEventListener('popstate', listener);

const pushUrl = (href) => {
  history.pushState({}, '', href);
  window.dispatchEvent(new Event('popstate'));
};

Solution 2

I use this script in my extension "Grab Any Media" and work fine ( like youtube case )

var oldHref = document.location.href;

window.onload = function() {
    var bodyList = document.querySelector("body")

    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (oldHref != document.location.href) {
                oldHref = document.location.href;
                /* Changed ! your code here */
            }
        });
    });
    
    var config = {
        childList: true,
        subtree: true
    };
    
    observer.observe(bodyList, config);
};

Solution 3

You can't avoid polling, there isn't any event for href change.

Using intervals is quite light anyways if you don't go overboard. Checking the href every 50ms or so will not have any significant effect on performance if you're worried about that.

Solution 4

There is a default onhashchange event that you can use.

Documented HERE

And can be used like this:

function locationHashChanged( e ) {
    console.log( location.hash );
    console.log( e.oldURL, e.newURL );
    if ( location.hash === "#pageX" ) {
        pageX();
    }
}

window.onhashchange = locationHashChanged;

If the browser doesn't support oldURL and newURL you can bind it like this:

//let this snippet run before your hashChange event binding code
if( !window.HashChangeEvent )( function() {
    let lastURL = document.URL;
    window.addEventListener( "hashchange", function( event ) {
        Object.defineProperty( event, "oldURL", { enumerable: true, configurable: true, value: lastURL } );
        Object.defineProperty( event, "newURL", { enumerable: true, configurable: true, value: document.URL } );
        lastURL = document.URL;
    } );
} () );

Solution 5

Through Jquery, just try

$(window).on('beforeunload', function () {
    //your code goes here on location change 
});

By using javascript:

window.addEventListener("beforeunload", function (event) {
   //your code goes here on location change 
});

Refer Document : https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload

Share:
237,472
Johan Dahlin
Author by

Johan Dahlin

Python, C developer.

Updated on November 10, 2021

Comments

  • Johan Dahlin
    Johan Dahlin over 2 years

    I'm writing a Greasemonkey script for a site which at some point modifies location.href.

    How can I get an event (via window.addEventListener or something similar) when window.location.href changes on a page? I also need access to the DOM of the document pointing to the new/modified url.

    I've seen other solutions which involve timeouts and polling, but I'd like to avoid that if possible.

  • Noslide
    Noslide over 13 years
    I'm not sure if this will work because often the hash changes do no involve a page reload.
  • Johan Dahlin
    Johan Dahlin over 13 years
    I need access to the new DOM as well, I updated the question to clarify that.
  • belugabob
    belugabob over 13 years
    OK - didn't consider the hash situation - will think about that one. As for being able to access the new DOM, then you are out of luck (as far as accesssing this from an event handler is concerned) as the event will fire before the new DOM has been loaded. You might be able to incorporate the logic into the onload event of the new page, but you may have the same issues with respect to identifying whether you need to carry out the logic for every load of that page. Can you provide some more details about what you are trying to achieve, including page flow?
  • CMCDragonkai
    CMCDragonkai about 7 years
    I just tried accessing the location.href inside the onbeforeunload event handler, and it shows the original url, not the target url.
  • user2782001
    user2782001 about 7 years
    But will the popstate fire before the content is loaded?
  • serv-inc
    serv-inc about 7 years
    @AlexanderMills: fortunately there are these new solutions of popstate and hashchange.
  • Guntram
    Guntram about 6 years
    Somehow, I like this approach... feels a little RxJs-ish :)
  • Simon Meusel
    Simon Meusel about 6 years
    The only solution that could have worked for youtube: [Report Only] Refused to create a worker from 'youtube.com/sw.js' because it violates the following Content Security Policy directive: "worker-src 'none'".
  • inf3rno
    inf3rno over 5 years
    This is not true.
  • inf3rno
    inf3rno over 5 years
    Beforeunload can cancel the unloading of the page, so the unload event is better, if you don't want to cancel navigation.
  • inf3rno
    inf3rno over 5 years
    @MartinZvarík Even in 2010 it was possible to use the unload event plus a micro or macro task to get the new document loaded.
  • Fredrik_Borgstrom
    Fredrik_Borgstrom over 5 years
    Hashchange events are only sent if your URL has a part starting with a '#' symbol, normally used for anchor links. Otherwise it won't fire.
  • Admin
    Admin over 4 years
    MutationObserver
  • Nathan Gouy
    Nathan Gouy about 4 years
    unusable if don't have any control over the piece of code that pushState
  • Bishoy Hanna
    Bishoy Hanna about 4 years
    window.addEventListener("hashchange", funcRef, false);
  • Sanchit Batra
    Sanchit Batra about 4 years
    Worked out of the box with no trouble for my use case, God bless! It's annoying there's no native event for this yet (popstate did not work for me) but one day! I would use window.addEventListener("load", () => {}) instead of window.onload though :)
  • YangombiUmpakati
    YangombiUmpakati about 4 years
    this works, detects history.pushState even in extension context
  • Rico Kahler
    Rico Kahler about 4 years
    Unfortunately this answer is still correct in 2020. popstate only fires when the user uses the forward/back buttons and hashchange only fires for hash changes. Unless you have control over the code that's causing the location to change, you have to poll 🤷‍♀️
  • TrySpace
    TrySpace almost 4 years
    This does not always work, it relies on a popstate event to be fired. For example navigating within youtube it won't trigger, only if you press back or forward in history
  • Eyal Cohen
    Eyal Cohen about 3 years
    man this is amazing. the smartest solution I've seen to date
  • mikey
    mikey about 3 years
    this assume you have visibility or know if pushState is called.. it won't work everywhere, like comments above state as well
  • Boontawee Home
    Boontawee Home about 3 years
    man this is amazing. work with shopee webpage.
  • Al Foиce    ѫ
    Al Foиce ѫ almost 3 years
    Code-only answers are not particularly helpful. Please add some descriptions of how this code solves the problem.
  • s.r.
    s.r. over 2 years
    This is the smartest solution to this problem (listening for changes in the body). Also works within React to detect URL changes. Thanks a lot!
  • TGrif
    TGrif over 2 years
    Just try it, doesn't work on Firefox.
  • Praveen Danagoudru
    Praveen Danagoudru over 2 years
    it's working, use javascript
  • S. W. G.
    S. W. G. about 2 years
    put this in content script but it is not firing.
  • SShah
    SShah about 2 years
    Hello I am new to using MutationObservers and love this solution,its the only one I found that worked sofar for YT redirects. Just wanted to note that you could make it more efficient by moving the if (oldHref != document.location.href) check before your forEach call as you would only need to do the check once.