Navigation Guards
You can register global before guards using router.beforeEach
:
Global before guards are called in creation order, whenever a navigation is triggered. Guards may be resolved asynchronously, and the navigation is considered pending before all hooks have been resolved.
Every guard function receives two arguments:
to
: the target route location in a normalized format being navigated to.from
: the current route location being navigated away from.
And can optionally return any of the following values:
false
: cancel the current navigation. If the browser URL was changed (either manually by the user or via back button), it will be reset to that of thefrom
route.- A Route Location: Redirect to a different location by passing a route location as if you were calling , which allows you to pass options like
replace: true
orname: 'home'
. The current navigation is dropped and a new one is created with the samefrom
.
It’s also possible to throw an Error
if an unexpected situation was met. This will also cancel the navigation and call any callback registered via router.onError()
.
If nothing, undefined
or true
is returned, the navigation is validated, and the next navigation guard is called.
All of the the things above work the same way with async
functions and Promises:
router.beforeEach(async (to, from) => {
// canUserAccess() returns `true` or `false`
const canAccess = await canUserAccess(to)
if (!canAccess) return '/login'
})
In previous versions of Vue Router, it was also possible to use a third argument next
, this was a common source of mistakes and went through an to remove it. However, it is still supported, meaning you can pass a third argument to any navigation guard. In that case, you must call next
exactly once in any given pass through a navigation guard. It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors. Here is a bad example of redirecting to user to /login
if they are not authenticated:
// BAD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// if the user is not authenticated, `next` is called twice
next()
})
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
Global Resolve Guards
You can register a global guard with router.beforeResolve
. This is similar to router.beforeEach
because it triggers on every navigation, but resolve guards are called right before the navigation is confirmed, after all in-component guards and async route components are resolved. Here is an example that ensures the user has given access to the Camera for routes that property requiresCamera
:
router.beforeResolve
is the ideal spot to fetch data or do any other operation that you want to avoid doing if the user cannot enter a page.
You can also register global after hooks, however unlike guards, these hooks do not get a next
function and cannot affect the navigation:
sendToAnalytics(to.fullPath)
})
They are useful for analytics, changing the title of the page, accessibility features like announcing the page and many other things.
They also reflect navigation failures as the third argument:
router.afterEach((to, from, failure) => {
if (!failure) sendToAnalytics(to.fullPath)
})
Learn more about navigation failures on .
Per-Route Guard
You can define beforeEnter
guards directly on a route’s configuration object:
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
beforeEnter
guards only trigger when entering the route, they don’t trigger when the params
, query
or hash
change e.g. going from /users/2
to /users/3
or going from /users/2#info
to /users/2#projects
. They are only triggered when navigating from a different route.
Note it is possible to achieve a similar behavior by using and global navigation guards.
Finally, you can directly define route navigation guards inside route components (the ones passed to the router configuration)
You can add the following options to route components:
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
const UserDetails = {
template: `...`,
beforeRouteEnter(to, from) {
// called before the route that renders this component is confirmed.
// does NOT have access to `this` component instance,
// because it has not been created yet when this guard is called!
},
beforeRouteUpdate(to, from) {
// called when the route that renders this component has changed,
// but this component is reused in the new route.
// For example, given a route with params `/users/:id`, when we
// will be reused, and this hook will be called when that happens.
// Because the component is mounted while this happens, the navigation guard has access to `this` component instance.
},
beforeRouteLeave(to, from) {
// called when the route that renders this component is about to
// be navigated away from.
// As with `beforeRouteUpdate`, it has access to `this` component instance.
},
}
The beforeRouteEnter
guard does NOT have access to this
, because the guard is called before the navigation is confirmed, thus the new entering component has not even been created yet.
However, you can access the instance by passing a callback to next
. The callback will be called when the navigation is confirmed, and the component instance will be passed to the callback as the argument:
beforeRouteEnter (to, from, next) {
next(vm => {
// access to component public instance via `vm`
})
}
Note that beforeRouteEnter
is the only guard that supports passing a callback to next
. For beforeRouteUpdate
and beforeRouteLeave
, this
is already available, so passing a callback is unnecessary and therefore not supported:
beforeRouteUpdate (to, from) {
// just use `this`
this.name = to.params.name
}
The leave guard is usually used to prevent the user from accidentally leaving the route with unsaved edits. The navigation can be canceled by returning false
.
If you are writing your component using the , you can add update and leave guards through onBeforeRouteUpdate
and onBeforeRouteLeave
respectively. Please refer to the Composition API section for more details.
The Full Navigation Resolution Flow
- Navigation triggered.
- Call
beforeRouteLeave
guards in deactivated components. - Call global
beforeEach
guards. - Call
beforeRouteUpdate
guards in reused components. - Call
beforeEnter
in route configs. - Resolve async route components.
- Call
beforeRouteEnter
in activated components. - Call global
beforeResolve
guards. - Navigation is confirmed.
- Call global
afterEach
hooks. - DOM updates triggered.