mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(router): Add a withNavigationErrorHandler feature to provideRouter (#48551)
`withNavigationErrorHandler` is a close replacement for the `RouterModule.forRoot.errorHandler` / `Router.errorHandler`. It provides a quick, short way for users to define a function to handle `NavigationError` events. PR Close #48551
This commit is contained in:
committed by
Alex Rickabaugh
parent
d887d69f24
commit
31b94c762f
@@ -396,13 +396,12 @@ available in `RouterModule.forRoot` or `provideRouter` and `withRouterConfig`.
|
||||
* `paramsInheritanceStrategy`
|
||||
* `urlUpdateStrategy`
|
||||
* `canceledNavigationResolution`
|
||||
* `errorHandler`
|
||||
|
||||
The following options are available in `RouterModule.forRoot` but not
|
||||
available in `provideRouter`:
|
||||
* `malformedUriErrorHandler` - This was not found to be used by anyone.
|
||||
There are currently no plans to make this available in `provideRouter`.
|
||||
* `errorHandler` - Developers should instead subscribe to `Router.events`
|
||||
and filter for `NavigationError`.
|
||||
|
||||
<a id="router-can-load"></a>
|
||||
|
||||
|
||||
@@ -246,6 +246,9 @@ export type DisabledInitialNavigationFeature = RouterFeature<RouterFeatureKind.D
|
||||
// @public
|
||||
export type EnabledBlockingInitialNavigationFeature = RouterFeature<RouterFeatureKind.EnabledBlockingInitialNavigationFeature>;
|
||||
|
||||
// @public
|
||||
export type ErrorHandlerFeature = RouterFeature<RouterFeatureKind.NavigationErrorHandlerFeature>;
|
||||
|
||||
// @public
|
||||
type Event_2 = RouterEvent | NavigationStart | NavigationEnd | NavigationCancel | NavigationError | RoutesRecognized | GuardsCheckStart | GuardsCheckEnd | RouteConfigLoadStart | RouteConfigLoadEnd | ChildActivationStart | ChildActivationEnd | ActivationStart | ActivationEnd | Scroll | ResolveStart | ResolveEnd | NavigationSkipped;
|
||||
export { Event_2 as Event }
|
||||
@@ -748,7 +751,7 @@ export interface RouterFeature<FeatureKind extends RouterFeatureKind> {
|
||||
}
|
||||
|
||||
// @public
|
||||
export type RouterFeatures = PreloadingFeature | DebugTracingFeature | InitialNavigationFeature | InMemoryScrollingFeature | RouterConfigurationFeature;
|
||||
export type RouterFeatures = PreloadingFeature | DebugTracingFeature | InitialNavigationFeature | InMemoryScrollingFeature | RouterConfigurationFeature | ErrorHandlerFeature;
|
||||
|
||||
// @public
|
||||
export type RouterHashLocationFeature = RouterFeature<RouterFeatureKind.RouterHashLocationFeature>;
|
||||
@@ -1071,6 +1074,9 @@ export function withDisabledInitialNavigation(): DisabledInitialNavigationFeatur
|
||||
// @public
|
||||
export function withEnabledBlockingInitialNavigation(): EnabledBlockingInitialNavigationFeature;
|
||||
|
||||
// @public
|
||||
export function withErrorHandler(fn: (error: NavigationError) => void): ErrorHandlerFeature;
|
||||
|
||||
// @public
|
||||
export function withHashLocation(): RouterConfigurationFeature;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export {ActivationEnd, ActivationStart, ChildActivationEnd, ChildActivationStart
|
||||
export {CanActivate, CanActivateChild, CanActivateChildFn, CanActivateFn, CanDeactivate, CanDeactivateFn, CanLoad, CanLoadFn, CanMatch, CanMatchFn, Data, DefaultExport, LoadChildren, LoadChildrenCallback, NavigationBehaviorOptions, OnSameUrlNavigation, QueryParamsHandling, Resolve, ResolveData, ResolveFn, Route, Routes, RunGuardsAndResolvers, UrlMatcher, UrlMatchResult} from './models';
|
||||
export {Navigation, NavigationExtras, UrlCreationOptions} from './navigation_transition';
|
||||
export {DefaultTitleStrategy, TitleStrategy} from './page_title_strategy';
|
||||
export {DebugTracingFeature, DisabledInitialNavigationFeature, EnabledBlockingInitialNavigationFeature, InitialNavigationFeature, InMemoryScrollingFeature, PreloadingFeature, provideRouter, provideRoutes, RouterConfigurationFeature, RouterFeature, RouterFeatures, RouterHashLocationFeature, withDebugTracing, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation, withHashLocation, withInMemoryScrolling, withPreloading, withRouterConfig} from './provide_router';
|
||||
export {DebugTracingFeature, DisabledInitialNavigationFeature, EnabledBlockingInitialNavigationFeature, InitialNavigationFeature, InMemoryScrollingFeature, NavigationErrorHandlerFeature as ErrorHandlerFeature, PreloadingFeature, provideRouter, provideRoutes, RouterConfigurationFeature, RouterFeature, RouterFeatures, RouterHashLocationFeature, withDebugTracing, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation, withHashLocation, withInMemoryScrolling, withNavigationErrorHandler as withErrorHandler, withPreloading, withRouterConfig} from './provide_router';
|
||||
export {BaseRouteReuseStrategy, DetachedRouteHandle, RouteReuseStrategy} from './route_reuse_strategy';
|
||||
export {Router} from './router';
|
||||
export {ExtraOptions, InitialNavigation, InMemoryScrollingOptions, ROUTER_CONFIGURATION, RouterConfigOptions} from './router_config';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {HashLocationStrategy, LOCATION_INITIALIZED, LocationStrategy, ViewportScroller} from '@angular/common';
|
||||
import {APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, ApplicationRef, ComponentRef, ENVIRONMENT_INITIALIZER, EnvironmentProviders, inject, InjectFlags, InjectionToken, Injector, makeEnvironmentProviders, NgZone, Provider, Type} from '@angular/core';
|
||||
import {APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, ApplicationRef, ComponentRef, ENVIRONMENT_INITIALIZER, EnvironmentInjector, EnvironmentProviders, inject, InjectFlags, InjectionToken, Injector, makeEnvironmentProviders, NgZone, Provider, Type} from '@angular/core';
|
||||
import {of, Subject} from 'rxjs';
|
||||
import {filter, map, take} from 'rxjs/operators';
|
||||
|
||||
@@ -621,6 +621,63 @@ export function withHashLocation(): RouterConfigurationFeature {
|
||||
return routerFeature(RouterFeatureKind.RouterConfigurationFeature, providers);
|
||||
}
|
||||
|
||||
/**
|
||||
* A type alias for providers returned by `withNavigationErrorHandler` for use with `provideRouter`.
|
||||
*
|
||||
* @see `withNavigationErrorHandler`
|
||||
* @see `provideRouter`
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export type NavigationErrorHandlerFeature =
|
||||
RouterFeature<RouterFeatureKind.NavigationErrorHandlerFeature>;
|
||||
|
||||
/**
|
||||
* Subscribes to the Router's navigation events and calls the given function when a
|
||||
* `NavigationError` happens.
|
||||
*
|
||||
* This function is run inside application's injection context so you can use the `inject` function.
|
||||
*
|
||||
* @usageNotes
|
||||
*
|
||||
* Basic example of how you can use the error handler option:
|
||||
* ```
|
||||
* const appRoutes: Routes = [];
|
||||
* bootstrapApplication(AppComponent,
|
||||
* {
|
||||
* providers: [
|
||||
* provideRouter(appRoutes, withNavigationErrorHandler((e: NavigationError) =>
|
||||
* inject(MyErrorTracker).trackError(e))
|
||||
* ]
|
||||
* }
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @see `NavigationError`
|
||||
* @see `inject`
|
||||
* @see `EnvironmentInjector#runInContext`
|
||||
*
|
||||
* @returns A set of providers for use with `provideRouter`.
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export function withNavigationErrorHandler(fn: (error: NavigationError) => void):
|
||||
NavigationErrorHandlerFeature {
|
||||
const providers = [{
|
||||
provide: ENVIRONMENT_INITIALIZER,
|
||||
multi: true,
|
||||
useValue: () => {
|
||||
const injector = inject(EnvironmentInjector);
|
||||
inject(Router).events.subscribe((e) => {
|
||||
if (e instanceof NavigationError) {
|
||||
injector.runInContext(() => fn(e));
|
||||
}
|
||||
});
|
||||
}
|
||||
}];
|
||||
return routerFeature(RouterFeatureKind.NavigationErrorHandlerFeature, providers);
|
||||
}
|
||||
|
||||
/**
|
||||
* A type alias that represents all Router features available for use with `provideRouter`.
|
||||
* Features can be enabled by adding special functions to the `provideRouter` call.
|
||||
@@ -632,7 +689,7 @@ export function withHashLocation(): RouterConfigurationFeature {
|
||||
* @publicApi
|
||||
*/
|
||||
export type RouterFeatures = PreloadingFeature|DebugTracingFeature|InitialNavigationFeature|
|
||||
InMemoryScrollingFeature|RouterConfigurationFeature;
|
||||
InMemoryScrollingFeature|RouterConfigurationFeature|NavigationErrorHandlerFeature;
|
||||
|
||||
/**
|
||||
* The list of features as an enum to uniquely type each feature.
|
||||
@@ -644,5 +701,6 @@ export const enum RouterFeatureKind {
|
||||
DisabledInitialNavigationFeature,
|
||||
InMemoryScrollingFeature,
|
||||
RouterConfigurationFeature,
|
||||
RouterHashLocationFeature
|
||||
RouterHashLocationFeature,
|
||||
NavigationErrorHandlerFeature,
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import {concat, EMPTY, Observable, Observer, of, Subscription} from 'rxjs';
|
||||
import {delay, filter, first, last, map, mapTo, takeWhile, tap} from 'rxjs/operators';
|
||||
|
||||
import {CanActivateChildFn, CanActivateFn, CanMatch, CanMatchFn, Data, ResolveFn} from '../src/models';
|
||||
import {provideRouter, withRouterConfig} from '../src/provide_router';
|
||||
import {provideRouter, withNavigationErrorHandler, withRouterConfig} from '../src/provide_router';
|
||||
import {forEach, wrapIntoObservable} from '../src/utils/collection';
|
||||
import {getLoadedRoutes} from '../src/utils/config';
|
||||
|
||||
@@ -1668,6 +1668,29 @@ describe('Integration', () => {
|
||||
]);
|
||||
})));
|
||||
|
||||
it('should be able to provide an error handler with DI dependencies', async () => {
|
||||
@Injectable({providedIn: 'root'})
|
||||
class Handler {
|
||||
handlerCalled = false;
|
||||
}
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
provideRouter(
|
||||
[{
|
||||
path: 'throw',
|
||||
canMatch: [() => {
|
||||
throw new Error('');
|
||||
}],
|
||||
component: BlankCmp
|
||||
}],
|
||||
withNavigationErrorHandler(() => coreInject(Handler).handlerCalled = true)),
|
||||
]
|
||||
});
|
||||
const router = TestBed.inject(Router);
|
||||
await expectAsync(router.navigateByUrl('/throw')).toBeRejected();
|
||||
expect(TestBed.inject(Handler).handlerCalled).toBeTrue();
|
||||
});
|
||||
|
||||
// Errors should behave the same for both deferred and eager URL update strategies
|
||||
['deferred', 'eager'].forEach((strat: any) => {
|
||||
it('should dispatch NavigationError after the url has been reset back', fakeAsync(() => {
|
||||
|
||||
Reference in New Issue
Block a user