How can I check if a URL has changed in JavaScript? For example, websites like GitHub, which use AJAX, will append page information after a # symbol to create a unique URL w
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.
I created this, just add the function as an argument and whenever the link has any changes it will run the function returning the old and new url
I created this, just add the function as an argument and whenever the link has any changes it will run the function returning the old and new url
// on-url-change.js v1 (manual verification)
let onUrlChangeCallbacks = [];
let onUrlChangeTimestamp = new Date() * 1;
function onUrlChange(callback){
onUrlChangeCallbacks.push(callback);
};
onUrlChangeAutorun();
function onUrlChangeAutorun(){
let oldURL = window.location.href;
setInterval(function(){
let newURL = window.location.href;
if(oldURL !== newURL){
let event = {
oldURL: oldURL,
newURL: newURL,
type: 'urlchange',
timestamp: new Date() * 1 - onUrlChangeTimestamp
};
oldURL = newURL;
for(let i = 0; i < onUrlChangeCallbacks.length; i++){
onUrlChangeCallbacks[i](event);
};
};
}, 25);
};
Add a hash change event listener!
window.addEventListener('hashchange', function(e){console.log('hash changed')});
Or, to listen to all URL changes:
window.addEventListener('popstate', function(e){console.log('url changed')});
This is better than something like the code below because only one thing can exist in window.onhashchange and you'll possibly be overwriting someone else's code.
// Bad code example
window.onhashchange = function() {
// Code that overwrites whatever was previously in window.onhashchange
}
use this code
window.onhashchange = function() {
//code
}
with jQuery
$(window).bind('hashchange', function() {
//code
});
To listen to url changes, see below:
window.onpopstate = function(event) {
console.log("location: " + document.location + ", state: " + JSON.stringify(event.state));
};
Use this style if you intend to stop/remove listener after some certain condition.
window.addEventListener('popstate', function(e) {
console.log('url changed')
});
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, 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'))
});