diff --git a/docs/guide/advanced/navigation-failures.md b/docs/guide/advanced/navigation-failures.md index ef759a89e..28274408e 100644 --- a/docs/guide/advanced/navigation-failures.md +++ b/docs/guide/advanced/navigation-failures.md @@ -10,15 +10,15 @@ When using a regular `router-link`, **none of these failures will log an error** ## Detecting Navigation Failures -_Navigation Failures_ are `Error` instances with a few extra properties. Among them, you can find a `type` property. This will allow you to check the type of the navigation failure: +_Navigation Failures_ are `Error` instances with a few extra properties. To check if an error comes from the Router, use the `isRouterError` function: ```js -import { NavigationFailureType } from 'vue-router' +import { NavigationFailureType, isRouterError } from 'vue-router' -// trying to access an admin-only route +// trying to access the admin page router.push('/admin').catch(failure => { if (failure) { - if (failure.type === NavigationFailureType.redirected) { + if (isRouterError(failure, NavigationFailureType.redirected)) { // show a small notification to the user showToast('Login in order to access the admin panel') } @@ -26,6 +26,10 @@ router.push('/admin').catch(failure => { }) ``` +::: tip +If you omit the second parameter: `isRouterError(failure)`, it will only check if the error comes from the Router. +::: + ## `NavigationFailureType` `NavigationFailureType` exposes the following properties to differentiate _Navigation Failures_: @@ -40,10 +44,10 @@ router.push('/admin').catch(failure => { Apart from exposing a `type` property, all navigation failures expose `to` and `from` properties to reflect the current location as well as the target location for the navigation that failed: ```js -// given we are at `/` +// trying to access the admin page router.push('/admin').catch(failure => { if (failure) { - if (failure.type === NavigationFailureType.redirected) { + if (isRouterError(failure, NavigationFailureType.redirected)) { failure.to.path // '/admin' failure.from.path // '/' } diff --git a/src/history/abstract.js b/src/history/abstract.js index 6de8ce269..6e8410a30 100644 --- a/src/history/abstract.js +++ b/src/history/abstract.js @@ -2,8 +2,7 @@ import type Router from '../index' import { History } from './base' -import { isRouterError } from '../util/warn' -import { NavigationFailureType } from '../util/errors' +import { NavigationFailureType, isRouterError } from '../util/errors' export class AbstractHistory extends History { index: number diff --git a/src/index.js b/src/index.js index ae3b69e15..1debc3016 100644 --- a/src/index.js +++ b/src/index.js @@ -16,22 +16,24 @@ import { AbstractHistory } from './history/abstract' import type { Matcher } from './create-matcher' +import { isRouterError, NavigationFailureType } from './util/errors' + export default class VueRouter { - static install: () => void; - static version: string; - - app: any; - apps: Array; - ready: boolean; - readyCbs: Array; - options: RouterOptions; - mode: string; - history: HashHistory | HTML5History | AbstractHistory; - matcher: Matcher; - fallback: boolean; - beforeHooks: Array; - resolveHooks: Array; - afterHooks: Array; + static install: () => void + static version: string + + app: any + apps: Array + ready: boolean + readyCbs: Array + options: RouterOptions + mode: string + history: HashHistory | HTML5History | AbstractHistory + matcher: Matcher + fallback: boolean + beforeHooks: Array + resolveHooks: Array + afterHooks: Array constructor (options: RouterOptions = {}) { this.app = null @@ -43,7 +45,8 @@ export default class VueRouter { this.matcher = createMatcher(options.routes || [], this) let mode = options.mode || 'hash' - this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false + this.fallback = + mode === 'history' && !supportsPushState && options.fallback !== false if (this.fallback) { mode = 'hash' } @@ -69,11 +72,7 @@ export default class VueRouter { } } - match ( - raw: RawLocation, - current?: Route, - redirectedFrom?: Location - ): Route { + match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route { return this.matcher.match(raw, current, redirectedFrom) } @@ -82,11 +81,12 @@ export default class VueRouter { } init (app: any /* Vue component instance */) { - process.env.NODE_ENV !== 'production' && assert( - install.installed, - `not installed. Make sure to call \`Vue.use(VueRouter)\` ` + - `before creating root instance.` - ) + process.env.NODE_ENV !== 'production' && + assert( + install.installed, + `not installed. Make sure to call \`Vue.use(VueRouter)\` ` + + `before creating root instance.` + ) this.apps.push(app) @@ -131,11 +131,15 @@ export default class VueRouter { history.setupListeners() handleInitialScroll(routeOrError) } - history.transitionTo(history.getCurrentLocation(), setupListeners, setupListeners) + history.transitionTo( + history.getCurrentLocation(), + setupListeners, + setupListeners + ) } history.listen(route => { - this.apps.forEach((app) => { + this.apps.forEach(app => { app._route = route }) }) @@ -204,11 +208,14 @@ export default class VueRouter { if (!route) { return [] } - return [].concat.apply([], route.matched.map(m => { - return Object.keys(m.components).map(key => { - return m.components[key] + return [].concat.apply( + [], + route.matched.map(m => { + return Object.keys(m.components).map(key => { + return m.components[key] + }) }) - })) + ) } resolve ( @@ -224,12 +231,7 @@ export default class VueRouter { resolved: Route } { current = current || this.history.current - const location = normalizeLocation( - to, - current, - append, - this - ) + const location = normalizeLocation(to, current, append, this) const route = this.match(location, current) const fullPath = route.redirectedFrom || route.fullPath const base = this.history.base @@ -267,6 +269,8 @@ function createHref (base: string, fullPath: string, mode) { VueRouter.install = install VueRouter.version = '__VERSION__' +VueRouter.isRouterError = isRouterError +VueRouter.NavigationFailureType = NavigationFailureType if (inBrowser && window.Vue) { window.Vue.use(VueRouter) diff --git a/src/util/errors.js b/src/util/errors.js index 140f181fa..9bc8b7a14 100644 --- a/src/util/errors.js +++ b/src/util/errors.js @@ -71,3 +71,11 @@ function stringifyRoute (to) { }) return JSON.stringify(location, null, 2) } + +export function isError (err) { + return Object.prototype.toString.call(err).indexOf('Error') > -1 +} + +export function isRouterError (err, errorType) { + return isError(err) && err._isRouter && (errorType == null || err.type === errorType) +} diff --git a/src/util/resolve-components.js b/src/util/resolve-components.js index 3f7608cd5..204e3ca8f 100644 --- a/src/util/resolve-components.js +++ b/src/util/resolve-components.js @@ -1,7 +1,8 @@ /* @flow */ import { _Vue } from '../install' -import { warn, isError } from './warn' +import { warn } from './warn' +import { isError } from '../util/errors' export function resolveAsyncComponents (matched: Array): Function { return (to, from, next) => { diff --git a/src/util/warn.js b/src/util/warn.js index 73e70caf8..025d3b20f 100644 --- a/src/util/warn.js +++ b/src/util/warn.js @@ -12,10 +12,3 @@ export function warn (condition: any, message: string) { } } -export function isError (err: any): boolean { - return Object.prototype.toString.call(err).indexOf('Error') > -1 -} - -export function isRouterError (err: any, errorType: ?string): boolean { - return isError(err) && err._isRouter && (errorType == null || err.type === errorType) -}