I have this code:
window.history.pushState(newUrl, "", newUrl);
My question is, how to make sure that when doing pushState the browser back button will function as normal or in other words should go "back"?
(without using jQUery)
The normal behaviour for the back button is for the browser to go back to the previous document, but when you use pushState, there isn't a previous document.
The point of pushState is to keep the browser on the same document while updating the URL. This is accompanied by DOM changes applied with JavaScript.
It is a simulation of going to a new page.
To make the back button appear to work, you need to write a matching simulation of going to the previous page.
You can do this by listening for a popstate event.
Page <span id="p">1</span>
<button>Next</button>
<script>
document.querySelector("button").addEventListener("click", function () {
document.getElementById('p').textContent++;
history.pushState({}, "", "/" + document.getElementById('p').textContent);
});
addEventListener("popstate", function (e) {
document.getElementById('p').textContent--;
e.preventDefault();
});
</script>
push is for pushing... adding
you should go for history.back()
If you want to popState - emit popstate event on window or do history.replaceState()
If you want to cancell commented event:
My answer will do the trick
https://stackoverflow.com/a/44553087/5694206
Related
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.
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();
I want to redirect client to custom controller when he click back browser button.
Do you know any clear ways to catch back button event and force to call server?
Bests,
Thank you
Back button question is quite well answered on SO. A quick search will turn up lots of extra information. Here is a bit of a summary.
You have a few strategies to choose from.
1 - If you are developing an SPA (or not) you may find making use of the history api useful.
https://developer.mozilla.org/en-US/docs/Web/API/History
https://developer.mozilla.org/en-US/docs/Web/API/History_API
You will find plenty on SO about history api.
Try starting here Preserve dynamically changed HTML on back button
Basically, by adding a listener for popstate event which fires everytime the active history entry changes :
(in jQuery)
$(document).ready(function () {
$(window).on('popstate' , function (event) {
console.log('popstate');
console.log(event);
console.log(event.originalEvent);
});
};
http://caniuse.com/#search=history
2 - add a listner for the pageshow event, will fire when a page load is completed and when session history entry is used for navigation, so basically forward & back buttons.
https://developer.mozilla.org/en-US/docs/Web/Events/pageshow
$(window).on('pageshow' , function (event) {
console.log('pageshow');
console.log(event);
console.log(event.originalEvent);
});
http://caniuse.com/#search=pageshow
3 - Append a hashvalues to your urls with window.location.hash = 'pageHashValue'.
Listen for hashchange event and you can then act based on the #value if needed.
https://developer.mozilla.org/en-US/docs/Web/Events/hashchange
This is a common approach in single page applications.
$(window).on('hashchange' , function (event) {
console.log('hashchange');
console.log(event);
console.log(event.originalEvent);
console.log(window.location.hash);
});
http://caniuse.com/#search=hashchange
Finally take note that while you, as a developer, no doubt hate the browser back button (like me) our users tend to love it. If you change the expected behavior of the back button you can also expect your user experience to be negatively affected. The best strategy is to use these events to maintain the expected behavior of the back button rather than to try and change it.
I need to know whether user clicked the back navigation arrow in browser. I Used the below event but not occur this event while i am clicking the back navigation arrow.
$(window).on("navigate", function (event, data) {
});
please suggest your answer If you know.
You might use the popstate of the history.
The popstate event is only triggered by doing a browser action such as clicking on the back button (or calling history.back() in JavaScript). And the event is only triggered when the user navigates between two history entries for the same document.
You'll have to add a new entry to history with the same title and no change to the url
pushState(state, title, url)
and when you intercept the onpopstate you will do your desired actions, unbind the event and then use the history.back() api.
window.onpopstate = function(event) {
alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
window.onpopstate = null;
history.back();
};
history.pushState({}, document.title, "");
This is not a proven method I've tested it just in Chrome.
Short answer - you can't.
Long answer - yoooooooooooouuuuuuuuuu caaaaaaaaannnnnnnnnn't.
At least not in the way that I think you're looking for. Best you can do is detect when user is leaving the page - though that doesn't necessarily mean that the back button was clicked. Also, you can't stop them leaving the page.
window.onbeforeunload = function(){
return 'Leave this page?';
};
Using the onbeforeunload event, you can run some arbitrary code - but the browser will show a modal dialog box asking the user whether they want to leave the page or remain on the page. You can't override this.
I've tried a few methods to see if I can create a cross browser solution for delaying a popstate event but have not had any luck.
Anyone have any ideas or thoughts?
Below obviously does not work, but something to the effect of:
$(window).on('popstate', function(e) {
// something here to delay the history pageload
console.log('a wild console has appeared!');
});
So the flow would follow this sequence:
Browser "back" or "forward" button clicked
run initial code
A delay before the page changes
page change
According to the Documentation the popstate event is
only triggered by doing a browser action such as a click on the back button
So I do not believe it will get triggered when user clicks 'forward' (and it varies in some browsers)
For reference, here's the full text:
The popstate event is fired when the active history entry changes. If the history entry being activated was created by a call to history.pushState() or was affected by a call to history.replaceState(), the popstate event's state property contains a copy of the history entry's state object.
Note that just calling history.pushState() or history.replaceState() won't trigger a popstate event. The popstate event is only triggered by doing a browser action such as a click on the back button (or calling history.back() in JavaScript).
Browsers tend to handle the popstate event differently on page load. Chrome (prior to v34) and Safari always emit a popstate event on page load, but Firefox doesn't.
UPDATED ANSWER ABOVE
Your code works. (see below) - I added an element to trigger the event (you can see the results in the console)
Make sure you include the jQuery library on your HTML prior to using it though.
$(window).on('popstate', function(e) {
console.log('fired instantly!');
var timer = setTimeout(function() {
console.log('delayed popstate!');
clearTimeout(timer);
}, 1000);
});
$(window).trigger( 'popstate') ;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
When linking to a page using a named anchor e.g. page.html#heading the browser will load the page, then jump down to the anchor. Is there a browser event that fires when this has completed?
To explain my reasons behind it: I want to use the event to trigger an animation in the browser.
Many thanks.
Changing the hash triggers the hashchange event.
However, I don't think it fires when loading a url where the link already has the hash set. But you can check the hash (location.hash) on page load if you want a certain script to run depending on the hash.
In Safari 7.0.3 on the Mac this works...
HTML has:
<a id="jumper" href="#aa">Jump</a>
JS:
<script>
var j = document.getElementById("jumper");
j.addEventListener("click", registerAnchorJump);
function registerAnchorJump(e) {
window.addEventListener("scroll", unregisterAnchorJump);
}
function unregisterAnchorJump(e) {
// trigger your animation...
console.log(window.scrollY);
window.removeEventListener("scroll",unregisterAnchorJump);
}
</script>
Fancy footwork to prevent constant firing of scroll event as user scrolls window normally.