8

If I'm currently at the URL"example.com/somepage#somehash" and I invoke window.location.hash = "anotherhash", the URL changes to "example.com/somepage#anotherhash". This fires the window.hashashchange event.

If I am currently at the URL "example.com/somepage?a=1&b=two" and I invoke window.location.replace("?one=1&two=2"), then the URL changes to "example.com/somepage?one=1&two=2".

I've read the MDN docs, and I can't find an even that this fires.

  1. Is there one?
  2. If not, is there a simple way to capture that event?

Note:

It's my fault for saying that I want to make sure I don't trigger a page reload. I want to use the new URL for updating the page based on the query string, for example with an AJAX request. window.history.pushState is another option, but as far as I can tell, it does not fire an event either.

Edit

I took a look at @Taki's answer. I create a repl.it because you can see the URL change when you go to the full-page view. However, even with the preventDefault the page is reloading, which is proved by the fact that the info posted to the page in the unload event callback disappears. Consequently, this can't be used for client-side routing, which is my goal.

index.html

<button id="myBtn">Click me</button>
<div id="info"></div>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="index.js"></script>

index.js

console.log("index.js");

$('#myBtn').on('click', function(e)
{
  console.log("button clicked")
  window.location.replace("?one=1&two=2")
  console.log(window.location.href);
});

$(window).on("beforeunload", function (event) 
{
  event.preventDefault(); // just to pause and see the cosdole
  console.log("beforeunload");
  console.log(event);
  $('#info').append("<p>beforeunload</p>");
  console.log(window.location.href); // capture the url
});
Cœur
  • 37,241
  • 25
  • 195
  • 267
abalter
  • 9,663
  • 17
  • 90
  • 145

3 Answers3

4

window.location.replace acts like a redirection, so you can listen for the BeforeUnload event

The Location.replace() method replaces the current resource with the one at the provided URL

( don't know why it can't replace the window.location in the snippet :P but it'll work outside it )

document.querySelector('#myBtn').addEventListener('click', function(){
  window.location.replace("?one=1&two=2")
});

window.addEventListener("beforeunload", function (event) {

  console.log(window.location.href); // capture the url
  event.preventDefault(); // just to pause and see the condole
  
});
<button id="myBtn">Click me</button>

EDIT :

apparently you can't prevent the page from reloading when changing location.href , but like you mentioned, you can use history.pushState and if it doesn't fire an event, create a custom one, attach it to the window and listen for it :

let evt = new CustomEvent('myEvent', ...
window.dispatchEvent(evt); 

... 

window.addEventListener('myEvent', function(e){ ...

this time it's working inside the snippet, see that it's not reloading and you get to keep urls in the history and you get your location

document.querySelectorAll('a').forEach(function(elem){
  
  elem.addEventListener('click', function(e){
   
    e.preventDefault();
    window.history.pushState("object or string", "Title", this.href);
    
    let evt = new CustomEvent('urlChange');
    window.dispatchEvent(evt);
    
  });
   
}); 

window.addEventListener('urlChange', function(e){
  document.querySelector('#myUrl').innerHTML = window.location.href;
});
#myUrl{
  display: block;
  font-size: 20px;
  margin-top: 20px;
}
<h1>hello</h1>
<a href="/one">Got to One</a><br />
<a href="/two">Got to Two</a><br />
<a href="?three=3">Got to Three</a><br />

<span id="myUrl"></span>
Taki
  • 17,320
  • 4
  • 26
  • 47
  • Thanks. I played with this, and I'm not sure it will work for me because it completely reloads the page anyway. – abalter Apr 07 '18 at 08:03
  • But that is my fault, because I did not say that I want to avoid a page reload. Changing the hash does not do that. – abalter Apr 07 '18 at 08:06
  • Use `pushState` and fire a custom `event` , check the edit – Taki Apr 08 '18 at 04:31
  • Yup. That would be the way to do it. Although it wouldn't be so much a custom event as another callback. So that I don't have to mess around, I'm just going to use a hash instead of "?" for the queries. Less traditional, but less code. – abalter Apr 08 '18 at 17:24
  • BTW--this really is a great example of a simple custom event. I will play with it some more. – abalter Apr 28 '18 at 06:05
1

no there is not such event, the simplest way to detect when something like this is about to happen is to set a proxy around the history https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

or you can just override the methods for it.

Dayan Moreno Leon
  • 5,357
  • 2
  • 22
  • 24
1

Try this:

navigation.addEventListener('navigate, (e) => {
   console.log(e.destination.url)
})

P.S. for Chrome 102+

Max
  • 11
  • 4