diff --git a/aio/content/guide/deprecations.md b/aio/content/guide/deprecations.md
index 718453baa71..6e4c47aad3e 100644
--- a/aio/content/guide/deprecations.md
+++ b/aio/content/guide/deprecations.md
@@ -117,6 +117,7 @@ v15 - v18
| `@angular/router` | [`RouterLinkWithHref` directive](#router) | v15 | v17 |
| `@angular/router` | [Router writeable properties](#router-writable-properties) | v15.1 | v17 |
| `@angular/router` | [Router CanLoad guards](#router-can-load) | v15.1 | v17 |
+| `@angular/router` | [class and `InjectionToken` guards and resolvers](#router) | v15.2 | v17 |
### Deprecated features with no planned removal version
@@ -203,6 +204,8 @@ In the [API reference section](api) of this site, deprecated APIs are indicated
| [`RouterLinkWithHref` directive](api/router/RouterLinkWithHref) | Use `RouterLink` instead. | v15 | The `RouterLinkWithHref` directive code was merged into `RouterLink`. Now the `RouterLink` directive can be used for all elements that have `routerLink` attribute. |
| [`provideRoutes` function](api/router/provideRoutes) | Use `ROUTES` `InjectionToken` instead. | v15 | The `provideRoutes` helper function is minimally useful and can be unintentionally used instead of `provideRouter` due to similar spelling. |
| [`setupTestingRouter` function](api/router/testing/setupTestingRouter) | Use `provideRouter` or `RouterTestingModule` instead. | v15.1 | The `setupTestingRouter` function is not necessary. The `Router` is initialized based on the DI configuration in tests as it would be in production. |
+| [class and `InjectionToken` guards and resolvers](api/router/DeprecatedGuard) | Use plain JavaScript functions instead. | v15.2 | Functional guards are simpler and more powerful than class and token-based guards. |
+
diff --git a/goldens/public-api/router/index.md b/goldens/public-api/router/index.md
index 11230f04e8f..452fca2902e 100644
--- a/goldens/public-api/router/index.md
+++ b/goldens/public-api/router/index.md
@@ -24,6 +24,7 @@ import { OnChanges } from '@angular/core';
import { OnDestroy } from '@angular/core';
import { OnInit } from '@angular/core';
import { Provider } from '@angular/core';
+import { ProviderToken } from '@angular/core';
import { QueryList } from '@angular/core';
import { Renderer2 } from '@angular/core';
import { SimpleChanges } from '@angular/core';
@@ -111,13 +112,13 @@ export abstract class BaseRouteReuseStrategy implements RouteReuseStrategy {
store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void;
}
-// @public
+// @public @deprecated
export interface CanActivate {
// (undocumented)
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree;
}
-// @public
+// @public @deprecated
export interface CanActivateChild {
// (undocumented)
canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree;
@@ -129,7 +130,7 @@ export type CanActivateChildFn = (childRoute: ActivatedRouteSnapshot, state: Rou
// @public
export type CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => Observable | Promise | boolean | UrlTree;
-// @public
+// @public @deprecated
export interface CanDeactivate {
// (undocumented)
canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot): Observable | Promise | boolean | UrlTree;
@@ -147,7 +148,7 @@ export interface CanLoad {
// @public @deprecated
export type CanLoadFn = (route: Route, segments: UrlSegment[]) => Observable | Promise | boolean | UrlTree;
-// @public
+// @public @deprecated
export interface CanMatch {
// (undocumented)
canMatch(route: Route, segments: UrlSegment[]): Observable | Promise | boolean | UrlTree;
@@ -237,6 +238,9 @@ export class DefaultUrlSerializer implements UrlSerializer {
serialize(tree: UrlTree): string;
}
+// @public @deprecated
+export type DeprecatedGuard = ProviderToken | any;
+
// @public
export type DetachedRouteHandle = {};
@@ -561,7 +565,7 @@ export function provideRoutes(routes: Routes): Provider[];
// @public
export type QueryParamsHandling = 'merge' | 'preserve' | '';
-// @public
+// @public @deprecated
export interface Resolve {
// (undocumented)
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | T;
@@ -569,7 +573,7 @@ export interface Resolve {
// @public
export type ResolveData = {
- [key: string | symbol]: any | ResolveFn;
+ [key: string | symbol]: ResolveFn | DeprecatedGuard;
};
// @public
@@ -611,12 +615,12 @@ export class ResolveStart extends RouterEvent {
// @public
export interface Route {
- canActivate?: Array;
- canActivateChild?: Array;
- canDeactivate?: Array | any>;
+ canActivate?: Array;
+ canActivateChild?: Array;
+ canDeactivate?: Array | DeprecatedGuard>;
// @deprecated
- canLoad?: Array;
- canMatch?: Array | InjectionToken | CanMatchFn>;
+ canLoad?: Array;
+ canMatch?: Array;
children?: Routes;
component?: Type;
data?: Data;
diff --git a/packages/router/src/index.ts b/packages/router/src/index.ts
index 3490400bc5d..c0dc153765c 100644
--- a/packages/router/src/index.ts
+++ b/packages/router/src/index.ts
@@ -12,7 +12,7 @@ export {RouterLink, RouterLinkWithHref} from './directives/router_link';
export {RouterLinkActive} from './directives/router_link_active';
export {RouterOutlet, RouterOutletContract} from './directives/router_outlet';
export {ActivationEnd, ActivationStart, ChildActivationEnd, ChildActivationStart, Event, EventType, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationCancellationCode as NavigationCancellationCode, NavigationEnd, NavigationError, NavigationSkipped, NavigationSkippedCode, NavigationStart, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouterEvent, RoutesRecognized, Scroll} from './events';
-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 {CanActivate, CanActivateChild, CanActivateChildFn, CanActivateFn, CanDeactivate, CanDeactivateFn, CanLoad, CanLoadFn, CanMatch, CanMatchFn, Data, DefaultExport, DeprecatedGuard, 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, NavigationErrorHandlerFeature, PreloadingFeature, provideRouter, provideRoutes, RouterConfigurationFeature, RouterFeature, RouterFeatures, RouterHashLocationFeature, withDebugTracing, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation, withHashLocation, withInMemoryScrolling, withNavigationErrorHandler, withPreloading, withRouterConfig} from './provide_router';
diff --git a/packages/router/src/models.ts b/packages/router/src/models.ts
index 201fcdfff6f..4f40dac61bc 100644
--- a/packages/router/src/models.ts
+++ b/packages/router/src/models.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {EnvironmentInjector, EnvironmentProviders, InjectionToken, NgModuleFactory, Provider, Type} from '@angular/core';
+import {EnvironmentInjector, EnvironmentProviders, NgModuleFactory, Provider, ProviderToken, Type} from '@angular/core';
import {Observable} from 'rxjs';
import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
@@ -38,6 +38,23 @@ import {UrlSegment, UrlSegmentGroup, UrlTree} from './url_tree';
*/
export type OnSameUrlNavigation = 'reload'|'ignore';
+/**
+ * The `InjectionToken` and `@Injectable` classes for guards and resolvers are deprecated in favor
+ * of plain JavaScript functions instead.. Dependency injection can still be achieved using the
+ * `inject` function from `@angular/core`.
+ *
+ * @deprecated
+ * @see CanMatchFn
+ * @see CanLoadFn
+ * @see CanActivateFn
+ * @see CanActivateChildFn
+ * @see CanDeactivateFn
+ * @see ResolveFn
+ * @see inject
+ * @publicApi
+ */
+export type DeprecatedGuard = ProviderToken|any;
+
/**
* Represents a route configuration for the Router service.
* An array of `Route` objects, used in `Router.config` and for nested route configurations
@@ -110,7 +127,7 @@ export type Data = {
* @publicApi
*/
export type ResolveData = {
- [key: string|symbol]: any|ResolveFn
+ [key: string|symbol]: ResolveFn|DeprecatedGuard
};
/**
@@ -517,7 +534,7 @@ export interface Route {
* When using a function rather than DI tokens, the function can call `inject` to get any required
* dependencies. This `inject` call must be done in a synchronous context.
*/
- canActivate?: Array;
+ canActivate?: Array;
/**
* An array of `CanMatchFn` or DI tokens used to look up `CanMatch()`
* handlers, in order to determine if the current user is allowed to
@@ -526,7 +543,7 @@ export interface Route {
* When using a function rather than DI tokens, the function can call `inject` to get any required
* dependencies. This `inject` call must be done in a synchronous context.
*/
- canMatch?: Array|InjectionToken|CanMatchFn>;
+ canMatch?: Array;
/**
* An array of `CanActivateChildFn` or DI tokens used to look up `CanActivateChild()` handlers,
* in order to determine if the current user is allowed to activate
@@ -535,7 +552,7 @@ export interface Route {
* When using a function rather than DI tokens, the function can call `inject` to get any required
* dependencies. This `inject` call must be done in a synchronous context.
*/
- canActivateChild?: Array;
+ canActivateChild?: Array;
/**
* An array of `CanDeactivateFn` or DI tokens used to look up `CanDeactivate()`
* handlers, in order to determine if the current user is allowed to
@@ -544,7 +561,7 @@ export interface Route {
* When using a function rather than DI tokens, the function can call `inject` to get any required
* dependencies. This `inject` call must be done in a synchronous context.
*/
- canDeactivate?: Array|any>;
+ canDeactivate?: Array|DeprecatedGuard>;
/**
* An array of `CanLoadFn` or DI tokens used to look up `CanLoad()`
* handlers, in order to determine if the current user is allowed to
@@ -554,7 +571,7 @@ export interface Route {
* dependencies. This `inject` call must be done in a synchronous context.
* @deprecated Use `canMatch` instead
*/
- canLoad?: Array;
+ canLoad?: Array;
/**
* Additional developer-defined data provided to the component via
* `ActivatedRoute`. By default, no additional data is passed.
@@ -696,6 +713,8 @@ export interface LoadedRouterConfig {
* ```
*
* @publicApi
+ * @deprecated Use plain JavaScript functions instead.
+ * @see CanActivateFn
*/
export interface CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
@@ -791,6 +810,8 @@ export type CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSn
* ```
*
* @publicApi
+ * @deprecated Use plain JavaScript functions instead.
+ * @see CanActivateChildFn
*/
export interface CanActivateChild {
canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot):
@@ -880,6 +901,8 @@ export type CanActivateChildFn = (childRoute: ActivatedRouteSnapshot, state: Rou
* ```
*
* @publicApi
+ * @deprecated Use plain JavaScript functions instead.
+ * @see CanDeactivateFn
*/
export interface CanDeactivate {
canDeactivate(
@@ -982,6 +1005,8 @@ export type CanDeactivateFn =
* ```
*
* @publicApi
+ * @deprecated Use plain JavaScript functions instead.
+ * @see CanMatchFn
*/
export interface CanMatch {
canMatch(route: Route, segments: UrlSegment[]):
@@ -1112,6 +1137,8 @@ export type CanMatchFn = (route: Route, segments: UrlSegment[]) =>
* The order of execution is: BaseGuard, ChildGuard, BaseDataResolver, ChildDataResolver.
*
* @publicApi
+ * @deprecated Use plain JavaScript functions instead.
+ * @see ResolveFn
*/
export interface Resolve {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable|Promise|T;
@@ -1196,7 +1223,7 @@ export type ResolveFn = (route: ActivatedRouteSnapshot, state: RouterStateSna
* ```
*
* @publicApi
- * @deprecated Use `CanMatch` instead
+ * @deprecated Use `CanMatchFn` instead
*/
export interface CanLoad {
canLoad(route: Route, segments: UrlSegment[]):
diff --git a/packages/router/src/operators/check_guards.ts b/packages/router/src/operators/check_guards.ts
index d832c5aebf9..2de2159766e 100644
--- a/packages/router/src/operators/check_guards.ts
+++ b/packages/router/src/operators/check_guards.ts
@@ -11,7 +11,7 @@ import {concat, defer, from, MonoTypeOperatorFunction, Observable, of, OperatorF
import {concatMap, first, map, mergeMap, tap} from 'rxjs/operators';
import {ActivationStart, ChildActivationStart, Event} from '../events';
-import {CanActivateChild, CanActivateChildFn, CanActivateFn, Route} from '../models';
+import {CanActivateChild, CanActivateChildFn, CanActivateFn, CanDeactivateFn, CanLoadFn, CanMatchFn, Route} from '../models';
import {redirectingNavigationError} from '../navigation_canceling_error';
import {NavigationTransition} from '../navigation_transition';
import {ActivatedRouteSnapshot, RouterStateSnapshot} from '../router_state';
@@ -142,7 +142,8 @@ function runCanActivateChild(
getTokenOrFunctionIdentity(canActivateChild, closestInjector);
const guardVal = isCanActivateChild(guard) ?
guard.canActivateChild(futureARS, futureRSS) :
- closestInjector.runInContext(() => guard(futureARS, futureRSS));
+ closestInjector.runInContext(
+ () => (guard as CanActivateChildFn)(futureARS, futureRSS));
return wrapIntoObservable(guardVal).pipe(first());
});
return of(guardsMapped).pipe(prioritizedGuardValue());
@@ -161,8 +162,8 @@ function runCanDeactivate(
const guard = getTokenOrFunctionIdentity(c, closestInjector);
const guardVal = isCanDeactivate(guard) ?
guard.canDeactivate(component, currARS, currRSS, futureRSS) :
- closestInjector.runInContext(
- () => guard(component, currARS, currRSS, futureRSS));
+ closestInjector.runInContext(
+ () => (guard as CanDeactivateFn)(component, currARS, currRSS, futureRSS));
return wrapIntoObservable(guardVal).pipe(first());
});
return of(canDeactivateObservables).pipe(prioritizedGuardValue());
@@ -180,7 +181,7 @@ export function runCanLoadGuards(
const guard = getTokenOrFunctionIdentity(injectionToken, injector);
const guardVal = isCanLoad(guard) ?
guard.canLoad(route, segments) :
- injector.runInContext(() => guard(route, segments));
+ injector.runInContext(() => (guard as CanLoadFn)(route, segments));
return wrapIntoObservable(guardVal);
});
@@ -213,7 +214,7 @@ export function runCanMatchGuards(
const guard = getTokenOrFunctionIdentity(injectionToken, injector);
const guardVal = isCanMatch(guard) ?
guard.canMatch(route, segments) :
- injector.runInContext(() => guard(route, segments));
+ injector.runInContext(() => (guard as CanMatchFn)(route, segments));
return wrapIntoObservable(guardVal);
});