Browser Back Button Handling

How to Detect Browser Back Button event - Cross Browser

(Note: As per Sharky's feedback, I've included code to detect backspaces)

So, I've seen these questions frequently on SO, and have recently run into the issue of controlling back button functionality myself. After a few days of searching for the best solution for my application (Single-Page with Hash Navigation), I've come up with a simple, cross-browser, library-less system for detecting the back button.

Most people recommend using:

window.onhashchange = function() {
//blah blah blah
}

However, this function will also be called when a user uses on in-page element that changes the location hash. Not the best user experience when your user clicks and the page goes backwards or forwards.

To give you a general outline of my system, I'm filling up an array with previous hashes as my user moves through the interface. It looks something like this:

function updateHistory(curr) {
window.location.lasthash.push(window.location.hash);
window.location.hash = curr;
}

Pretty straight forward. I do this to ensure cross-browser support, as well as support for older browsers. Simply pass the new hash to the function, and it'll store it for you and then change the hash (which is then put into the browser's history).

I also utilise an in-page back button that moves the user between pages using the lasthash array. It looks like this:

function goBack() {
window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
//blah blah blah
window.location.lasthash.pop();
}

So this will move the user back to the last hash, and remove that last hash from the array (I have no forward button right now).

So. How do I detect whether or not a user has used my in-page back button, or the browser button?

At first I looked at window.onbeforeunload, but to no avail - that is only called if the user is going to change pages. This does not happen in a single-page-application using hash navigation.

So, after some more digging, I saw recommendations for trying to set a flag variable. The issue with this in my case, is that I would try to set it, but as everything is asynchronous, it wouldn't always be set in time for the if statement in the hash change. .onMouseDown wasn't always called in click, and adding it to an onclick wouldn't ever trigger it fast enough.

This is when I started to look at the difference between document, and window. My final solution was to set the flag using document.onmouseover, and disable it using document.onmouseleave.

What happens is that while the user's mouse is inside the document area (read: the rendered page, but excluding the browser frame), my boolean is set to true. As soon as the mouse leaves the document area, the boolean flips to false.

This way, I can change my window.onhashchange to:

window.onhashchange = function() {
if (window.innerDocClick) {
window.innerDocClick = false;
} else {
if (window.location.hash != '#undefined') {
goBack();
} else {
history.pushState("", document.title, window.location.pathname);
location.reload();
}
}
}

You'll note the check for #undefined. This is because if there is no history available in my array, it returns undefined. I use this to ask the user if they want to leave using a window.onbeforeunload event.

So, in short, and for people that aren't necessarily using an in-page back button or an array to store the history:

document.onmouseover = function() {
//User's mouse is inside the page.
window.innerDocClick = true;
}

document.onmouseleave = function() {
//User's mouse has left the page.
window.innerDocClick = false;
}

window.onhashchange = function() {
if (window.innerDocClick) {
//Your own in-page mechanism triggered the hash change
} else {
//Browser back button was clicked
}
}

And there you have it. a simple, three-part way to detect back button usage vs in-page elements with regards to hash navigation.

EDIT:

To ensure that the user doesn't use backspace to trigger the back event, you can also include the following (Thanks to @thetoolman on this Question):

$(function(){
/*
* this swallows backspace keys on any non-input element.
* stops backspace -> back
*/
var rx = /INPUT|SELECT|TEXTAREA/i;

$(document).bind("keydown keypress", function(e){
if( e.which == 8 ){ // 8 == backspace
if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
e.preventDefault();
}
}
});
});

Browser back button handling

Warn/confirm User if Back button is Pressed is as below.

window.onbeforeunload = function() { return "Your work will be lost."; };

You can get more information using below mentioned links.

Disable Back Button in Browser using JavaScript

I hope this will help to you.

Intercept/handle browser's back button in React-router?

here is how I ended up doing it:

componentDidMount() {
this._isMounted = true;
window.onpopstate = ()=> {
if(this._isMounted) {
const { hash } = location;
if(hash.indexOf('home')>-1 && this.state.value!==0)
this.setState({value: 0})
if(hash.indexOf('users')>-1 && this.state.value!==1)
this.setState({value: 1})
if(hash.indexOf('data')>-1 && this.state.value!==2)
this.setState({value: 2})
}
}
}

thanks everybody for helping lol

Scroll to top on browser back button click react

I don't think the beforeunload event is necessary here, but will include it anyway. Instead of using an event listener for the "popstate" event you can use the useNavigationType hook to expressly check for a POP event type.

Note: Use window.addEventListener for the beforeunload event so you don't pollute/mutate the window object.

Example:

import { NavigationType, useLocation, useNavigationType } from "react-router-dom";

const useBackButton = () => {
const navType = useNavigationType();
return navType === NavigationType.Pop;
};

const useScrollToTop = () => {
const { pathname } = useLocation();

const isPop = useBackButton();

const scrollToTop = () => window.scrollTo(0, 0);

useEffect(() => {
scrollToTop();
}, [pathname, isPop]);

useEffect(() => {
window.addEventListener("beforeunload", scrollToTop);
return () => {
window.removeEventListener("beforeunload", scrollToTop);
};
}, []);
};

Usage:

function App() {
useScrollToTop();

return (
...
);
}

Edit scroll-to-top-on-browser-back-button-click-react

How does the Back button in a web browser work?

Your web browser keeps a stack (or list, if you will) of the web pages that you have visited in that window. Let's say your home page is search.example and from there you visit a few other websites: video.example, portal.example, and news.example. Upon visiting the last one, the list looks like this:

search.example -> video.example -> portal.example -> news.example
^
|
current page

When you press the Back button, the browser takes you back to the previous page in the list, like this:

search.example -> video.example -> portal.example -> news.example
^
|
current page

At this point you can press Back again to take you to video.example, or you can press Forward to put you at news.example again. Let's say you press Back a second time:

search.example -> video.example -> portal.example -> news.example
^
|
current page

If you now go to, say, example.com, the list changes to look like this:

search.example -> video.example -> example.com
^
|
current page

Note that both portal.example and news.example are gone from the list. This is because you took a new route. The browser only maintains a list the pages you visited to get to where you are now, not a history of every page you've ever been to. The browser also doesn't know anything about the structure of the site you're visiting, which can lead to some surprising behavior.

You're on a shopping site (shop.example, as a short example) that has categories and subcategories of products to browse through. The site designer has thoughtfully provided breadcrumbs near the top of the window to allow you to navigate through the categories. You start at the top page of the site, click on Hardware, then Memory. The list now looks like this:

search.example -> shop.example -> shop.example/hw -> shop.example/hw/mem
^
|
current page

You want to go back to the Hardware category, so you use the breadcrumbs to go up to the parent category instead of using the Back button. Now the browser list looks like this:

search.example -> shop.example -> shop.example/hw -> shop.example/hw/mem -> shop.example/hw
^
|
current page

According to the site structure, you went backward (up a level), but to the browser you went forward because you clicked on a link. Any time you click on a link or type in a URL in the address bar, you are going forward as far as the browser is concerned, whether or not that link takes you to a page that you've already been to.

Finally, you want to return to the main site page (shop.example). You could use the breadcrumbs, but this time you click the Back button -- it seems obvious that it should take you up one level, right? But where does it take you?

It's initially confusing to many users (myself included, when I happen to do exactly this) that it takes you "down" a level, back to the Memory category. Looking at the list of pages, it's easy to see why:

search.example -> shop.example -> shop.example/hw -> shop.example/hw/mem -> shop.example/hw
^
|
current page

To go back to the main page using only the Back button would require two more presses, taking you "back" to the Hardware category and finally to the main page. It seems so obvious to us programmers what's going on, but it surprises the heck out of regular users all the time because they don't realize that the browser doesn't know anything about the hierarchical structure of whatever website they happen to be on.

Would it be great if browsers would let site designers program the Back button to do the obvious thing (take you up a level) rather than whatever it does now?

A commenter asked whether the browser reloads the page or simply displays it out of its local cache.

The answer is it depends. Site designers can specify whether the browser should cache the page or not. For pages that are set as non-cached, the browser reloads the page from the server when you press Back, as though it was the first time you are visiting it. For cached pages, the browser displays it out of the cache, which is much faster.



Related Topics



Leave a reply



Submit