Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to listen for changes to window.location.search in 2019

I would like to update window.location.search without reloading the document and then execute a function based on the updated values in window.location.search.

When the user clicks a button, that button's onclick event fires the following function:

window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');

So far so good. The window.location.search updates in the browser URL bar.

But I can't find a general background event listener which detects this update - something like onhashchange but for query strings.

The best I can come up with is:

window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
window.history.back();

window.addEventListener('popstate', () => console.log(event.state.action));

This works but I'm convinced there must be a more elegant approach.

like image 697
Rounin - Glory to UKRAINE Avatar asked Sep 21 '19 11:09

Rounin - Glory to UKRAINE


People also ask

How does Windows location search work?

Window location.search The search property returns the querystring part of a URL, including the question mark (?). The search property can also be used to set the querystring.

What is window location host?

host. The host property of the Location interface is a string containing the host, that is the hostname, and then, if the port of the URL is nonempty, a ':' , and the port of the URL.


1 Answers

Final Answer:

I was mostly happy with the Second Attempt answer immediately below.

But I really didn't like:

history.back();
history.forward();

which I adopted to trigger the popstate event, manually.

In practice, I found this hack worked sometimes, it was slow at other times and on occasion it failed completely.

On paper, it feels too makeshift.

After repeatedly searching and experimenting (this was remarkably hard to find), I have finally found the correct syntax for manually firing a popstate event.

It's as simple as dispatching this:

new Event('popstate')

Like this:

let myEvent = new Event('popstate');
window.dispatchEvent(myEvent);

So the final code is:

window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
let queryStringChange = new Event('popstate');
window.dispatchEvent(queryStringChange);

Best Answer I can come up with (Second Attempt):

Building on the following:

I know for certain that the query-string will only need to be checked either:

  1. when the page loads or reloads;

  2. when window.history.pushstate is invoked;

  3. or when (as @Kaiido astutely pointed out in the comments below) a page is accessed via the forward and back buttons

I also know that:

  • The window.load event listener covers Point 1.;
  • The window.popstate event listener covers Point 3.;

This only leaves Point 2.


Dealing with Point 2

As MDN reports:

Note that just calling history.pushState() or history.replaceState() won't trigger a popstate event. The popstate event will be triggered by doing a browser action such as a click on the back or forward button (or calling history.back() or history.forward() in JavaScript).

Source: https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event

But this means that rather than using (as in my first attempt, below):

window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');

checkQueryString(); // DIRECT INVOCATION OF FUNCTION

I can use instead:

window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
history.back();
history.forward();

This means that rather than needing to invoke the function directly, I can now allow the same window.popstate event listener covering Point 3 to do its work, giving me cleaner, more logically separated code.


N.B. I find it... weird... that pressing the forward button alone will fire the window.popstate event listener, but invoking window.history.pushState() will not... (necessitating the immediately subsequent addition of history.back(); history.forward(); to duplicate the functionality of a forward button).

But, as above, this is the best, cleanest, most optimised (in terms of logical separation and future code maintenance) solution I can come up with. If anyone has a dramatically better idea, I'll be happy to transfer the green tick.


First Attempt at an Answer:

I am tentatively concluding that there is no way to achieve this effect using a background event listener which can detect when the query string updates.

Instead, since I know for certain that the query-string will only need to be checked either:

  • when the page loads or reloads
  • when window.history.pushstate is invoked

I can use the following:

window.addEventListener('load', checkQueryString);

and

window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');

checkQueryString();
like image 66
Rounin - Glory to UKRAINE Avatar answered Oct 31 '22 16:10

Rounin - Glory to UKRAINE