There is no JavaScript event for a URL change. There is one, however, for when the fragment changes (the part after the #
symbol), called hashchange
, and there is another, popstate
, which doesn't always get triggered, for when the user clicks on the back or forward buttons or the history.back()
or history.go()
methods are called.
To detect if a URL changes, there are a couple of arguably hacky options:
- Store the URL in a variable and compare it against
location.href
every once in a while (polling) to see if it changed:
function doSomething() {
console.log('URL change detected!');
}
let currentUrl = location.href;
setInterval(() => {
if (location.href !== currentUrl) {
currentUrl = location.href;
doSomething();
}
}, 500);
console.log('URL change detected!');
}
let currentUrl = location.href;
setInterval(() => {
if (location.href !== currentUrl) {
currentUrl = location.href;
doSomething();
}
}, 500);
- Replace the
history.*
methods with custom ones that trigger a manual event (this is uglier in my opinion, and I haven't tested it much):
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'))
});
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'))
});
Final thoughts
Both methods strike me as awful from an "engineering elegance" point of view, but what is web development if not an endless sequence of terrible decisions?