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:
when the page loads or reloads;
when window.history.pushstate
is invoked;
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();
popstate
event in order to catch when your user will navigate through the browser's back-next buttons. – Lamellate