In my Vue app, a user's homepage depends on their role. To ensure that a user is shown the correct homepage, I use this navigation guard:
export default (to, from, next) => {
const authService = getAuthService()
if (to.path === '/') {
// if they've requested the home page, send them to
// different pages depending on their role
if (authService.isUser()) {
next({ name: 'events' })
} else if (authService.isAdmin()) {
next({ name: 'admin-events' })
} else {
next()
}
}
}
Then when a user successfully logs in, I redirect them to '/'
this.$router.push({path: '/'))
and the nav guard above redirects them to their role-specific homepage. However, redirecting twice in the course of a single navigation action is not allowed and causes the following error to appear in the console when the second redirection occurs (in the nav guard) `
Uncaught (in promise) Error: Redirected when going from
"/login"
to"/"
via a navigation guard.
Another case in my app where this happens is the 404 component that handles attempts to access non-existent routes, i.e.
'/'
Is there a way I can support these use cases without redirecting twice?
tldr: vm.$router.push(route)
is a promise and needs to .catch(e=>gotCaught(e))
errors.
This will be changed in the next major@4
Currently@3 errors are not distinguished whether they are NavigationFailures
or regular Errors
.
The naive expected route after vm.$router.push(to)
should be to
. Thus one can expect some failure message once there was a redirect. Before patching router.push to be a promise the error was ignored silently.
The current solution is to antipattern a .catch(...)
onto every push, or to anticipate the change in design and wrap it to expose the failure as result.
Future plans have it to put those informations into the result:
let failure = await this.$router.push(to);
if(failure.type == NavigationFailureType[type]){}
else{}
Imo this error is just by design and should be handled:
hook(route, current, (to: any) => { ... abort(createNavigationRedirectedError(current, route)) ...}
So basically if to
contains a redirect it is an error, which kinda is equal to using vm.$router.push
into a guard.
To ignore the unhandled error behaviour one can pass an empty onComplete (breaks in future releases):
vm.$router.push(Route, ()=>{})
or wrap it in try .. catch
try {
await this.$router.push("/")
} catch {
}
which prevents the promise to throw uncaught.
to support this without redirecting twice means you put the guard to your exit:
let path = "/"
navguard({path}, undefined, (to)=>this.$router.push(to||path))
which will polute every component redirecting to home
btw the router-link
component uses an empty onComplete
Assumption that redirecting twice is not allowed is wrong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With