Prevent user from exiting a route
See original GitHub issueFor example, say the user is halfway through typing a message in a blog post; if they click on a link that could take them away from the route, we need the ability to cancel the route change. Which we do, using triggersExit
and stop()
.
However, the reality is more complex; we don’t want to stop the user from changing routes, only warn them that they will lose data if they do and give them a cancel option. So we popup a modal with a confirm / cancel option. The problem now is that this requires a callback, so the triggersExit
function returns without having called stop()
and thus continues, regardless of the user choice.
Could we not have a continue()
function that must be called in order for the route to change, or alternatively a callback(cancel)
type method structure?
Issue Analytics
- State:
- Created 8 years ago
- Comments:22 (5 by maintainers)
Top GitHub Comments
I have put together the following workaround for this problem that effectively ‘prevents’ route changes when needed, e.g. when the user has unsaved changes. This allows other code to rely on the router to enforce handling unsaved changes, without needing to run additional checks.
It seems we can’t simply stop() unwanted route changes without having an inconsistent address bar, so my approach ‘rewinds’ the route change as cleanly as possible. It copes nicely with the user pressing the browser back button.
In the code below, If there are unsaved changes,
preventRouteChange()
useswindow.confirm()
to prompt the user synchronously, using the browser’s built-in prompt. This is the most robust approach because it blocks the viewport and prevents the user from clicking the back/forward buttons. Alternatively, you might usesetTimeout
to fire off an asynchronous warning prompt of your own design after the route change has been prevented:targetContext
provides the user’s intended destination for your ‘yes’ callback. But beware, if you do this, the user can still press the back/forward buttons while your prompt is displayed! So be sure to handle that if necessary.Where appropriate, I recommend combining this solution with
window.onbeforeunload
which will also catch attempts to navigate away from the app - e.g. closing the browser window. Another benefit of usingwindow.confirm()
is that the prompt looks and functions the same as thewindow.onbeforeunload
prompt, which means you have the same user experience for both navigating away and closing the window.Obviously, it would be better if it were possible to prevent route changes globally, but this is currently not possible.
One last point that came up with all of this: Perhaps FlowRouter should detect dangerous calls to
go()
within route triggers, and handle them better - e.g. queue them for execution, or abort current route handling and move to the new route requested bygo()
? My workaround was to wrap the call insetTimeout()
.I’d be interested to hear your comments.
Up here, Do we have an “official way” to do this now ?