How to detect if URL has changed after hash in JavaScript

I wanted to be able to add locationchange event listeners. After the modification below, we'll be able to do it, like this

window.addEventListener('locationchange', function(){
    console.log('location changed!');
})

In contrast, window.addEventListener('hashchange',()=>{}) would only fire if the part after a hashtag in a url changes, and window.addEventListener('popstate',()=>{}) doesn't always work.

This modification, similar to Christian's answer, modifies the history object to add some functionality.

By default, before these modifications, there's a popstate event, but there are no events for pushstate, and replacestate.

This modifies these three functions so that all fire a custom locationchange event for you to use, and also pushstate and replacestate events if you want to use those.

These are the modifications:

history.pushState = ( f => function pushState(){
    var ret = f.apply(this, arguments);
    window.dispatchEvent(new Event('pushstate'));
    window.dispatchEvent(new Event('locationchange'));
    return ret;
})(history.pushState);

history.replaceState = ( f => function replaceState(){
    var ret = f.apply(this, arguments);
    window.dispatchEvent(new Event('replacestate'));
    window.dispatchEvent(new Event('locationchange'));
    return ret;
})(history.replaceState);

window.addEventListener('popstate',()=>{
    window.dispatchEvent(new Event('locationchange'))
});

Note:

We're creating a closure, old = (f=>function new(){f();...})(old) replaces old with a new function that contains the previous old saved within it (old is not run at this moment, but it will be run inside of new)


In modern browsers (IE8+, FF3.6+, Chrome), you can just listen to the hashchange event on window.

In some old browsers, you need a timer that continually checks location.hash. If you're using jQuery, there is a plugin that does exactly that.


window.onhashchange = function() { 
     //code  
}

window.onpopstate = function() { 
     //code  
}

or

window.addEventListener('hashchange', function() { 
  //code  
});

window.addEventListener('popstate', function() { 
  //code  
});

with jQuery

$(window).bind('hashchange', function() {
     //code
});

$(window).bind('popstate', function() {
     //code
});

EDIT after a bit of researching:

It somehow seems that I have been fooled by the documentation present on Mozilla docs. The popstate event (and its callback function onpopstate) are not triggered whenever the pushState() or replaceState() are called in code. Therefore the original answer does not apply in all cases.

However there is a way to circumvent this by monkey-patching the functions according to @alpha123:

var pushState = history.pushState;
history.pushState = function () {
    pushState.apply(history, arguments);
    fireEvents('pushState', arguments);  // Some event-handling function
};

Original answer

Given that the title of this question is "How to detect URL change" the answer, when you want to know when the full path changes (and not just the hash anchor), is that you can listen for the popstate event:

window.onpopstate = function(event) {
  console.log("location: " + document.location + ", state: " + JSON.stringify(event.state));
};

Reference for popstate in Mozilla Docs

Currently (Jan 2017) there is support for popstate from 92% of browsers worldwide.