Navigation Guards
As the name suggests, the navigation guards provided by vue-router
are primarily used to guard navigations either by redirecting it or canceling it. There are a number of ways to hook into the route navigation process: globally, per-route, or in-component.
Remember that params or query changes won't trigger enter/leave navigation guards. You can either watch the $route
object to react to those changes, or use the beforeRouteUpdate
in-component guard.
Global Before Guards
You can register global before guards using router.beforeEach
:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
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 three arguments:
to: Route
: the target Route Object being navigated to.from: Route
: the current route being navigated away from.next: Function
: this function must be called to resolve the hook. The action depends on the arguments provided tonext
:next()
: move on to the next hook in the pipeline. If no hooks are left, the navigation is confirmed.next(false)
: abort 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.next('/')
ornext({ path: '/' })
: redirect to a different location. The current navigation will be aborted and a new one will be started. You can pass any location object tonext
, which allows you to specify options likereplace: true
,name: 'home'
and any option used inrouter-link
'sto
prop orrouter.push
next(error)
: (2.4.0+) if the argument passed tonext
is an instance ofError
, the navigation will be aborted and the error will be passed to callbacks registered viarouter.onError()
.
Make sure to always call the next
function, otherwise the hook will never be resolved.
Global Resolve Guards
You can register a global guard with router.beforeResolve
. This is similar to router.beforeEach
, with the difference that resolve guards will be called right before the navigation is confirmed, after all in-component guards and async route components are resolved.
Global After Hooks
You can also register global after hooks, however unlike guards, these hooks do not get a next
function and cannot affect the navigation:
router.afterEach((to, from) => {
// ...
})
Per-Route Guard
You can define beforeEnter
guards directly on a route's configuration object:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
These guards have the exact same signature as global before guards.
In-Component Guards
Finally, you can directly define route navigation guards inside route components (the ones passed to the router configuration) with the following options:
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 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, next) {
// called when the route that renders this component has changed,
// but this component is reused in the new route.
// For example, for a route with dynamic params `/foo/:id`, when we
// navigate between `/foo/1` and `/foo/2`, the same `Foo` component instance
// will be reused, and this hook will be called when that happens.
// has access to `this` component instance.
},
beforeRouteLeave (to, from, next) {
// called when the route that renders this component is about to
// be navigated away from.
// 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 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, next) {
// just use `this`
this.name = to.params.name
next()
}
The leave guard is usually used to prevent the user from accidentally leaving the route with unsaved edits. The navigation can be canceled by calling next(false)
.
beforeRouteLeave (to, from, next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
The Full Navigation Resolution Flow
- Navigation triggered.
- Call leave 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 confirmed.
- Call global
afterEach
hooks. - DOM updates triggered.
- Call callbacks passed to
next
inbeforeRouteEnter
guards with instantiated instances.