feat(router): add support for custom error handlers
This commit is contained in:
parent
93f323cfa2
commit
2fc5c57b31
|
@ -201,6 +201,21 @@ export class RoutesRecognized {
|
||||||
export type Event =
|
export type Event =
|
||||||
NavigationStart | NavigationEnd | NavigationCancel | NavigationError | RoutesRecognized;
|
NavigationStart | NavigationEnd | NavigationCancel | NavigationError | RoutesRecognized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error handler that is invoked when a navigation errors.
|
||||||
|
*
|
||||||
|
* If the handler retuns a value, the navigation promise will be resolved with this value.
|
||||||
|
* If the handler throws an exception, the navigation promise will be rejected with
|
||||||
|
* the exception.
|
||||||
|
*
|
||||||
|
* @stable
|
||||||
|
*/
|
||||||
|
export type ErrorHandler = (error: any) => any;
|
||||||
|
|
||||||
|
function defaultErrorHandler(error: any): any {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `Router` is responsible for mapping URLs to components.
|
* The `Router` is responsible for mapping URLs to components.
|
||||||
*
|
*
|
||||||
|
@ -216,6 +231,8 @@ export class Router {
|
||||||
private navigationId: number = 0;
|
private navigationId: number = 0;
|
||||||
private configLoader: RouterConfigLoader;
|
private configLoader: RouterConfigLoader;
|
||||||
|
|
||||||
|
errorHandler: ErrorHandler = defaultErrorHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if at least one navigation happened.
|
* Indicates if at least one navigation happened.
|
||||||
*
|
*
|
||||||
|
@ -533,7 +550,11 @@ export class Router {
|
||||||
resolvePromise(false);
|
resolvePromise(false);
|
||||||
} else {
|
} else {
|
||||||
this.routerEvents.next(new NavigationError(id, this.serializeUrl(url), e));
|
this.routerEvents.next(new NavigationError(id, this.serializeUrl(url), e));
|
||||||
rejectPromise(e);
|
try {
|
||||||
|
resolvePromise(this.errorHandler(e));
|
||||||
|
} catch (ee) {
|
||||||
|
rejectPromise(ee);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.currentRouterState = storedState;
|
this.currentRouterState = storedState;
|
||||||
this.currentUrlTree = storedUrl;
|
this.currentUrlTree = storedUrl;
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {Route, Routes} from './config';
|
||||||
import {RouterLink, RouterLinkWithHref} from './directives/router_link';
|
import {RouterLink, RouterLinkWithHref} from './directives/router_link';
|
||||||
import {RouterLinkActive} from './directives/router_link_active';
|
import {RouterLinkActive} from './directives/router_link_active';
|
||||||
import {RouterOutlet} from './directives/router_outlet';
|
import {RouterOutlet} from './directives/router_outlet';
|
||||||
import {Router} from './router';
|
import {ErrorHandler, Router} from './router';
|
||||||
import {ROUTES} from './router_config_loader';
|
import {ROUTES} from './router_config_loader';
|
||||||
import {RouterOutletMap} from './router_outlet_map';
|
import {RouterOutletMap} from './router_outlet_map';
|
||||||
import {ActivatedRoute} from './router_state';
|
import {ActivatedRoute} from './router_state';
|
||||||
|
@ -137,11 +137,18 @@ export function provideRoutes(routes: Routes): any {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Extra options used to configure the router.
|
||||||
|
*
|
||||||
|
* Set `enableTracing` to log router events to the console.
|
||||||
|
* Set 'useHash' to true to enable HashLocationStrategy.
|
||||||
|
* Set `errorHandler` to enable a custom ErrorHandler.
|
||||||
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export interface ExtraOptions {
|
export interface ExtraOptions {
|
||||||
enableTracing?: boolean;
|
enableTracing?: boolean;
|
||||||
useHash?: boolean;
|
useHash?: boolean;
|
||||||
|
errorHandler?: ErrorHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupRouter(
|
export function setupRouter(
|
||||||
|
@ -156,6 +163,10 @@ export function setupRouter(
|
||||||
componentType, urlSerializer, outletMap, location, injector, loader, compiler,
|
componentType, urlSerializer, outletMap, location, injector, loader, compiler,
|
||||||
flatten(config));
|
flatten(config));
|
||||||
|
|
||||||
|
if (opts.errorHandler) {
|
||||||
|
r.errorHandler = opts.errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
if (opts.enableTracing) {
|
if (opts.enableTracing) {
|
||||||
r.events.subscribe(e => {
|
r.events.subscribe(e => {
|
||||||
console.group(`Router Event: ${(<any>e.constructor).name}`);
|
console.group(`Router Event: ${(<any>e.constructor).name}`);
|
||||||
|
|
|
@ -427,6 +427,23 @@ describe('Integration', () => {
|
||||||
]);
|
]);
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
it('should support custom error handlers', fakeAsync(inject([Router], (router: Router) => {
|
||||||
|
router.errorHandler = (error) => 'resolvedValue';
|
||||||
|
const fixture = createRoot(router, RootCmp);
|
||||||
|
|
||||||
|
router.resetConfig([{path: 'user/:name', component: UserCmp}]);
|
||||||
|
|
||||||
|
const recordedEvents: any[] = [];
|
||||||
|
router.events.forEach(e => recordedEvents.push(e));
|
||||||
|
|
||||||
|
let e: any;
|
||||||
|
router.navigateByUrl('/invalid').then(_ => e = _);
|
||||||
|
advance(fixture);
|
||||||
|
expect(e).toEqual('resolvedValue');
|
||||||
|
|
||||||
|
expectEvents(recordedEvents, [[NavigationStart, '/invalid'], [NavigationError, '/invalid']]);
|
||||||
|
})));
|
||||||
|
|
||||||
it('should replace state when path is equal to current path',
|
it('should replace state when path is equal to current path',
|
||||||
fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
||||||
const fixture = createRoot(router, RootCmp);
|
const fixture = createRoot(router, RootCmp);
|
||||||
|
|
|
@ -72,6 +72,7 @@ export declare type Event = NavigationStart | NavigationEnd | NavigationCancel |
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export interface ExtraOptions {
|
export interface ExtraOptions {
|
||||||
enableTracing?: boolean;
|
enableTracing?: boolean;
|
||||||
|
errorHandler?: ErrorHandler;
|
||||||
useHash?: boolean;
|
useHash?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +169,7 @@ export interface Route {
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare class Router {
|
export declare class Router {
|
||||||
config: Routes;
|
config: Routes;
|
||||||
|
errorHandler: ErrorHandler;
|
||||||
events: Observable<Event>;
|
events: Observable<Event>;
|
||||||
/** @experimental */ navigated: boolean;
|
/** @experimental */ navigated: boolean;
|
||||||
routerState: RouterState;
|
routerState: RouterState;
|
||||||
|
|
Loading…
Reference in New Issue