Skip to content

Commit c4ff27a

Browse files
committed
add beforeResolve hook
1 parent 7ae4d90 commit c4ff27a

File tree

6 files changed

+53
-23
lines changed

6 files changed

+53
-23
lines changed

docs/en/advanced/data-fetching.md

+16-19
Original file line numberDiff line numberDiff line change
@@ -84,31 +84,28 @@ export default {
8484
},
8585
beforeRouteEnter (to, from, next) {
8686
getPost(to.params.id, (err, post) => {
87-
if (err) {
88-
// display some global error message
89-
next(false)
90-
} else {
91-
next(vm => {
92-
vm.post = post
93-
})
94-
}
87+
next(vm => vm.setData(err, post))
9588
})
9689
},
9790
// when route changes and this component is already rendered,
9891
// the logic will be slightly different.
99-
watch: {
100-
$route () {
101-
this.post = null
102-
getPost(this.$route.params.id, (err, post) => {
103-
if (err) {
104-
this.error = err.toString()
105-
} else {
106-
this.post = post
107-
}
108-
})
92+
beforeRouteUpdate (to, from, next) {
93+
this.post = null
94+
getPost(to.params.id, (err, post) => {
95+
this.setData(err, post)
96+
next()
97+
})
98+
},
99+
methods: {
100+
setData (err, post) {
101+
if (err) {
102+
this.error = err.toString()
103+
} else {
104+
this.post = post
105+
}
109106
}
110107
}
111108
}
112109
```
113110

114-
The user will stay on the current view while the resource is being fetched for the incoming view. It is therefore recommended to display a progress bar or some kind of indicator while the data is being fetched. If the data fetch fails, it's also necessary to display some kind of global warning message.
111+
The user will stay on the previous view while the resource is being fetched for the incoming view. It is therefore recommended to display a progress bar or some kind of indicator while the data is being fetched. If the data fetch fails, it's also necessary to display some kind of global warning message.

docs/en/advanced/navigation-guards.md

+24-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
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.
44

5-
Remember **Params or queries changes won't trigger navigation guards**. Simply [watch the `$route` object](../essentials/dynamic-matching.md#reacting-to-params-changes) to react to those changes.
5+
Remember that **params or query changes won't trigger enter/leave navigation guards**. You can either [watch the `$route` object](../essentials/dynamic-matching.md#reacting-to-params-changes) to react to those changes, or use the `beforeRouteUpadte` in-component guard.
66

77
### Global Guards
88

@@ -36,6 +36,14 @@ Every guard function receives three arguments:
3636

3737
**Make sure to always call the `next` function, otherwise the hook will never be resolved.**
3838

39+
### Global Resolve Guards
40+
41+
> New in 2.5.0
42+
43+
In 2.5.0+ you can register a global guard with `router.onResolve`. 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**.
44+
45+
### Global After Hooks
46+
3947
You can also register global after hooks, however unlike guards, these hooks do not get a `next` function and cannot affect the navigation:
4048

4149
``` js
@@ -109,3 +117,18 @@ beforeRouteEnter (to, from, next) {
109117
```
110118

111119
You can directly access `this` inside `beforeRouteLeave`. 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)`.
120+
121+
### The Full Guard Resolution Flow
122+
123+
1. Navigation triggered
124+
2. Call leave guards in deactivated components
125+
3. Call global `beforeEach` guards
126+
4. Call `beforeRouteUpdate` guards in reused components (2.2+)
127+
5. Call `beforeEnter` in route configs
128+
6. Resolve async route components
129+
7. Call `beforeRouteEnter` in activated components
130+
8. Call global `beforeResolve` guards (2.5+)
131+
9. Navigation confirmed.
132+
10. Call global `afterEach` hooks.
133+
11. DOM updates triggered.
134+
12. Call callbacks passed to `next` in `beforeRouteEnter` guards with instantiated instances.

docs/en/api/router-instance.md

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
### Methods
2424

2525
- **router.beforeEach(guard)**
26+
- **router.beforeResolve(guard)** (2.5.0+)
2627
- **router.afterEach(hook)**
2728

2829
Add global navigation guards. See [Navigation Guards](../advanced/navigation-guards.md).

src/history/base.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,11 @@ export class History {
147147
runQueue(queue, iterator, () => {
148148
const postEnterCbs = []
149149
const isValid = () => this.current === route
150-
const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)
151150
// wait until async components are resolved before
152151
// extracting in-component enter guards
153-
runQueue(enterGuards, iterator, () => {
152+
const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)
153+
const queue = enterGuards.concat(this.router.resolveHooks)
154+
runQueue(queue, iterator, () => {
154155
if (this.pending !== route) {
155156
return abort()
156157
}

src/index.js

+6
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ export default class VueRouter {
2929
matcher: Matcher;
3030
fallback: boolean;
3131
beforeHooks: Array<?NavigationGuard>;
32+
resolveHooks: Array<?NavigationGuard>;
3233
afterHooks: Array<?((to: Route, from: Route) => any)>;
3334

3435
constructor (options: RouterOptions = {}) {
3536
this.app = null
3637
this.apps = []
3738
this.options = options
3839
this.beforeHooks = []
40+
this.resolveHooks = []
3941
this.afterHooks = []
4042
this.matcher = createMatcher(options.routes || [], this)
4143

@@ -120,6 +122,10 @@ export default class VueRouter {
120122
this.beforeHooks.push(fn)
121123
}
122124

125+
onResolve (fn: Function) {
126+
this.resolveHooks.push(fn)
127+
}
128+
123129
afterEach (fn: Function) {
124130
this.afterHooks.push(fn)
125131
}

types/router.d.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ declare class VueRouter {
2121
currentRoute: Route;
2222

2323
beforeEach (guard: NavigationGuard): void;
24+
onResolve (guard: NavigationGuard): void;
2425
afterEach (hook: (to: Route, from: Route) => any): void;
2526
push (location: RawLocation, onComplete?: Function, onAbort?: Function): void;
2627
replace (location: RawLocation, onComplete?: Function, onAbort?: Function): void;
2728
go (n: number): void;
2829
back (): void;
2930
forward (): void;
3031
getMatchedComponents (to?: RawLocation): Component[];
31-
onReady (cb: Function): void;
32+
onReady (cb: Function, errorCb?: Function): void;
33+
onError (cb: Function): void;
3234
addRoutes (routes: RouteConfig[]): void;
3335
resolve (to: RawLocation, current?: Route, append?: boolean): {
3436
location: Location;

0 commit comments

Comments
 (0)