If the user presses the back button, i am displaying a confirm dialog. Based on the user choice in the dialog, navigation is prevented or continues.
Here is the code for the same:
$rootScope.$on('$stateChangeStart', function(e) {
if(confirm('u want to leave the page?') != true){
e.preventDefault();
}
});
its working fine. The problem i have is, lets say,
The user is in 'Page2' when he presses the back button(he came there from Page0 -> Page1 -> Page2), user stays in 'Page2' if he chooses cancel in the dialog. But when he presses back button again, it takes him to 'Page0'.
I need to keep the history from changing if he chooses to not navigate back in the dialog.
How can i achieve this?
Thanks in advance.
Consider using
window.history.back()
window.history.forward();
In order to navigate Browser History.
Full API is described here:
https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history
Related
I am using React 17 and react-router-dom 5.2.
I have a left sidebar and a main content area.
Each page opened directly via URL, or via click on a link in the navbar it opens a page.
Each page has an entry route such as:
<Route path="/testpage" component={TestComponent} />
I need to detect if a person entered the page via keyboard or via some other way (mouse click, or direct url entered).
Each compnent has a header:
If a person enters via mouse click or entering the direct URL in the browser nothing changes.
If the person clicked the TAB key until the right link is focused in the navbar, and then the person presses ENTER in the keyboard, the page changes.
And in this case the tabindex should be 1 - <TestHeader title="" tabIndex={0} />
I am wondering how can I create a state in this component that holds the information if the page was loaded via keybaord or not...
Ideally I would have that line as the following:
<TestHeader title="" tabIndex={enteredByKeyboard ? 1 : 0} />
I hope somebody can help
To acknowledge if the user has pressed "Enter" key can be achieved via listening to keypress event. The addional logic can take place after the key press is captured.
// Execute a function when the user presses a key on the keyboard
input.addEventListener("keypress", function(event) {
// If the user presses the "Enter" key on the keyboard
if (event.key === "Enter") {
// Cancel the default action, if needed
event.preventDefault();
// Trigger the button element with a click
document.getElementById("myBtn").click();
// run the custom logic
// extract this line at the component level,
// (as the effects can only be utilised there
// const navigate = useNavigate();
const calculateRequiredRoute = event.target.value;
// modify the line above to achieve the desired name of that route
navigate(calculateRequiredRoute);
}
});
This way it would
Refer :
https://reactrouter.com/en/main/components/navigate
https://reactrouter.com/en/main/hooks/use-navigate
Edit:
keydown event can be used for better result, just when the key press was down, instead of on release of the pressed-key.
I'm trying to achieve the following with Gatsby
The user is on a form page, if they hit the browser back button, a pop up would appear, asking if they want to leave.
If the user selects ok, then it would go back.
If the user selects cancel, then it would stay on this page
I was able to "almost" make it happen by doing the following
useEffect(() => {
const confirmExit = e => {
const leaveThisPage = window.confirm("Would you like to leave this page?")
if (!leaveThisPage) {
window.history.forward()
}
}
window.addEventListener("popstate", confirmExit)
return () => {
window.removeEventListener("popstate", confirmExit)
}
}, [])
There is one issue, if the user selects cancel, then the browser would go to the previous page. Then window.history.forward() would fire and sends them back.
I noticed that popstate event cannot be cancelled, so e.preventDefault() won't work.
Note: I also tried to test with window.onbeforeunload, but it only triggers if I close to window, or if my previous is from outside my app. Is there a work around for my issue?
Gatsby is using #reach/router under the hood, which doesn't support intercepting and preventing navigation (emphasis mine):
No history blocking. I found that the only use-case I had was preventing the user from navigating away from a half-filled out form. Not only is it pretty easy to just save the form state to session storage and bring it back when they return, but history blocking doesn’t happen when you navigate away from the app (say to another domain). This kept me from actually using history blocking and always opting to save the form state to session storage. (Source)
I second the recommendation for saving the form state using localStorage.
I have an AngularJS app and use the following code to let the user confirm if s/he really wants to leave the page and might loose unsaved data:
window.addEventListener('beforeunload', function (e) {
e.preventDefault();
e.returnValue = '';
return 'Do you really want to leave?'
});
window.addEventListener('unload', function (e) {
console.log('unload');
myRestService.close();
e.preventDefault();
e.returnValue = '';
});
This works well and the browser displays the message box where the user has to decide to leave or to stay on the page. However, if the user really wants to leave the page, I have to make a call to a rest backend. For that I thought that I can also register for the unload event that is fired when the user actually leaves the back. That works if the user reloads the back or navigates to a different url within the app. However, the event is not fired, or at least I can't see it, when the user navigates to anthoer page or closes the browser.
How can I also catch these events and make sure that my rest call still goes through?
You can call a function before tab close like this:
$window.onbeforeunload = function (arg) {
$scope.onclose();
}
and now you can all your rest api in close function
for more detail and other methods follow this link
I'm using this.props.history.push('/', { signOut: true }) for when user clicks a button.
It does work, but even though I refresh / the data is always persisted. How can I make it so it only happens once (when a user clicks a button), then I'm able to handle the logic :)
Are there any other ways to do this? Would love the help ;c
I was able to prevent navigation as per the v4 docs, but I'm trying to hook up a function so that I can use a modal instead of an alert.
Function:
abandonForm = (route) => {
this.props.showModal('confirm');
console.log('leaving..');
}
In my page:
<NavigationPrompt when={true} message={(location) => this.abandonForm('confirm')} />
this.props.showModal('confirm') activates the modal successfully, but behind the modal the page still transitions - how can I prevent transition until a button in the modal is clicked?
Browsers only allow navigation cancellation by means of the alert box that you've mentioned. This restriction is motivated by phishing/scamming sites that try to use javascript gimmicks to create user experiences that convincingly mimic something that a browser or the OS would do (whom the user trusts). Even the format of the text shown in the alert box is crafted so that it's obvious that it originates from the site.
Of course, as long as the current URL stays within your app, you have control over it using react-router's history. For example you can do the following on navigation:
allow the navigation without confirmation
immediately navigate back to the previous location, but now with a modal on top
navigate away for real this time when the user clicks on a button in the modal.
The disadvantage of this approach (leaving out the sheer complexity of it) is that the user will not get a confirmation dialog if they try to navigate to a different site entirely.
Use:
this.unBlock = this.props.history.block((location, navigateToSelectedRoute) => {
// save navigateToSelectedRoute eg this.navigateToSelectedRoute =
// navigateToSelectedRoute;
// use this.navigateToSelectedRoute() afterwards to navigate to link
// show custom modal using setState
});
and when unblocking is done then call this.unBlock() to remove the listener.
Documentation here for history api