Reputation: 3548
Update :- As Akansh Gulati
Pointed out in his answer if user have any interaction with the page before clicking back button this will work as expected and if user do not have any interaction with the page and press back button then any entry in history ( either by hash-change or by history.push/replace ) will be ignored which is part of Google Chrome update will stop websites hijacking your browser back button
This is valid and logical answer so I am accepting his answer
I am trying to show a success popup after page load and if user press android back button ( which is in this case equivalent to browser back button ) I only want to close the popup ( don't want to redirect back on payment page )
I am adding hash in url when popup is open but when user press back button chrome ignore the hash and redirect back on previous page instead of just removing the hash ( working fine in Firefox )
I have a working example here use following HTML code to reproduce
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body onload="test()">
<button type="button" onclick="window.history.back();">Back</button>
</body>
<script type="text/javascript">
function writeLength() {
document.body.appendChild(document.createTextNode(window.history.length));
}
function test() {
window.location.hash = 'a';
setTimeout(function() {
writeLength();
window.location.hash = 'b';
setTimeout(function() {
writeLength();
window.location.hash = 'c';
setTimeout(function() {
writeLength();
}, 1500);
}, 1500);
}, 1500);
}
</script>
</html>
a) open this page in chrome
b) wait till hash is changed to '#c'
c) then press browser back button
expected behavior is it should change the hash back to '#b' and then back to '#a' but it ignore all the hash changes and redirect back to new-tab page
This is the code
window.location.hash = 'a';
setTimeout(function() {
writeLength();
window.location.hash = 'b';
setTimeout(function() {
writeLength();
window.location.hash = 'c';
setTimeout(function() {
writeLength();
}, 1500);
}, 1500);
}, 1500);
how can I simulate the correct behavior (if there is any way) ?
I am using chrome Version 77.0.3865.90 (Official Build) (64-bit) on Mac
here is a GIF image of behavior
Upvotes: 5
Views: 5873
Reputation: 1785
I tried using pushState for further location changes and the problem seems solved. No need to replaceState. The condition is only that user must have clicked/interacted atleast once with screen.
function test() {
window.location.hash = 'a';
setTimeout(function () {
writeLength();
window.history.pushState(null, null, `${window.location.pathname}#b`);
setTimeout(function () {
writeLength();
window.history.pushState(null, null, `${window.location.pathname}#c`);
setTimeout(function () {
writeLength();
}, 1500);
}, 1500);
}, 1500);
}
Upvotes: 4
Reputation: 107
I'm able to get the code your provided working on the same version of Chrome on Windows 10, but if you're still having issues the following should work.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body onload="test()">
<div id="url"></div>
<button type="button" onclick="window.history.back();">Back</button>
</body>
<script type="text/javascript">
setInterval(function(){
document.getElementById('url').innerHTML = window.location.href;
}, 500);
function writeLength() {
document.body.appendChild(document.createTextNode(window.history.length));
}
function test() {
history.pushState({},'','#a');
setTimeout(function() {
writeLength();
history.pushState({},'','#b');
setTimeout(function() {
writeLength();
history.pushState({},'','#c');
setTimeout(function() {
writeLength();
}, 1500);
}, 1500);
}, 1500);
}
</script>
</html>
This should work because window.pushState
should force the hash change to be added to the browser's history. If you want to update the page of a navigation change, you can use the window.onpopstate
event. For example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body onload="test()">
<div id="url"></div>
<button type="button" onclick="window.history.back();">Back</button>
<span id="lengths"></span>
</body>
<script type="text/javascript">
setInterval(function(){
document.getElementById('url').innerHTML = window.location.href;
}, 500);
var last = false;
var items = [];
function writeLength() {
items.push(window.history.length);
document.getElementById('lengths').appendChild(document.createTextNode(window.history.length));
}
function test() {
history.pushState({},'','#a');
setTimeout(function() {
writeLength();
history.pushState({},'','#b');
setTimeout(function() {
writeLength();
history.pushState({},'','#c');
setTimeout(function() {
writeLength();
last = true;
}, 1500);
}, 1500);
}, 1500);
}
window.onpopstate = function(){
if (last) {
if (window.location.hash == '#a') document.getElementById('lengths').innerHTML = items[0];
else if (window.location.hash == '#b') document.getElementById('lengths').innerHTML = '' + items[0] + items[1];
else if (window.location.hash == '#c') document.getElementById('lengths').innerHTML = '' + items[0] + items[1]+ items[2];
}
}
</script>
</html
The code above allows the user to navigate to different "states" of the page after the final length has been written to the document.
Upvotes: 0
Reputation: 181
You have to set your state explicitly, and you can execute some code when you click the back button, like this:
Add a function to get the window.location.href
without the hash part (because we will add it explicitly):
function getUrlWithoutTheHash() {
let url = window.location.href;
let hash = window.location.hash;
let index_of_hash = url.indexOf(hash) || url.length;
return url.substr(0, index_of_hash);
}
Add a function to push state (rather than changing the hash using the location, we change it using the state API) and we will add an attribute is-my-state
to the state to know if this is our state or not:
function pushTheState(url) {
history.pushState({'is-my-state': true, 'url': url}, null, url);
}
And add a handler when you open the state, and if this was one of your states, you can execute a desired code:
window.onpopstate = function(e){
if(e.state){
if(e.state.hasOwnProperty('is-my-state')){
writeLength();
}
}
};
Finally, you need to change your function like this:
function test() {
pushTheState(getUrlWithoutTheHash() + '#a'); // pushing url with #a
setTimeout(function() {
writeLength();
pushTheState(getUrlWithoutTheHash() + '#b'); // pushing url with #b
setTimeout(function() {
writeLength();
pushTheState(getUrlWithoutTheHash() + '#c'); // pushing url with #c
setTimeout(function() {
writeLength();
}, 1500);
}, 1500);
}, 1500);
}
Upvotes: 0
Reputation: 136658
In this browser you need to explicitly set at least one state in the History through the History API (not sure why though).
The example should work even in this iframe.
history.replaceState( {}, '' );
window.location.hash = 'a';
setTimeout(function() {
console.log( location.hash );
window.location.hash = 'b';
setTimeout(function() {
console.log( location.hash );
window.location.hash = 'c';
setTimeout(function() {
console.log( location.hash );
console.log( "You can now use your browser's back button" );
onpopstate = e => console.log( location.hash );
}, 150);
}, 150);
}, 150);
Upvotes: 5