From abe3759e2417c0396d75e226edcef2fae99e363b Mon Sep 17 00:00:00 2001 From: Dmitrij Kuba Date: Wed, 22 Jun 2022 18:52:57 +0300 Subject: [PATCH] fix(router): allow to return `UrlTree` from `CanMatchFn` (#46455) Currently it's not possible to return plain `UrlTree` from `CanMatchFn`, only wrapped `UrlTree` into Observable or Promise is allowed. These changes allow to return `UrlTree` from `CanMatchFn`. PR Close #46455 --- goldens/public-api/router/index.md | 2 +- packages/router/src/models.ts | 2 +- packages/router/test/integration.spec.ts | 24 +++++++++++++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/goldens/public-api/router/index.md b/goldens/public-api/router/index.md index a7d81826f25..b5281d015f9 100644 --- a/goldens/public-api/router/index.md +++ b/goldens/public-api/router/index.md @@ -142,7 +142,7 @@ export interface CanMatch { } // @public -export type CanMatchFn = (route: Route, segments: UrlSegment[]) => Observable | Promise | boolean; +export type CanMatchFn = (route: Route, segments: UrlSegment[]) => Observable | Promise | boolean | UrlTree; // @public export class ChildActivationEnd { diff --git a/packages/router/src/models.ts b/packages/router/src/models.ts index a4167a92e51..3ebd5e7b190 100644 --- a/packages/router/src/models.ts +++ b/packages/router/src/models.ts @@ -915,7 +915,7 @@ export interface CanMatch { * @see `Route` */ export type CanMatchFn = (route: Route, segments: UrlSegment[]) => - Observable|Promise|boolean; + Observable|Promise|boolean|UrlTree; /** * @description diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index b0d535a8395..2dc95e686b0 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -16,7 +16,7 @@ import {ActivatedRoute, ActivatedRouteSnapshot, ActivationEnd, ActivationStart, import {EMPTY, Observable, Observer, of, Subscription} from 'rxjs'; import {delay, filter, first, map, mapTo, tap} from 'rxjs/operators'; -import {CanMatch} from '../src/models'; +import {CanMatch, CanMatchFn} from '../src/models'; import {forEach} from '../src/utils/collection'; import {getLoadedRoutes} from '../src/utils/config'; import {RouterTestingModule} from '../testing'; @@ -4788,6 +4788,28 @@ describe('Integration', () => { const fixture = createRoot(router, RootCmp); + router.navigateByUrl('/a'); + advance(fixture); + expect(fixture.nativeElement.innerHTML).toContain('team'); + })); + + it('can return UrlTree from CanMatchFn guard', fakeAsync(() => { + const canMatchTeamSection = new InjectionToken('CanMatchTeamSection'); + const canMatchFactory: (router: Router) => CanMatchFn = (router: Router) => () => + router.createUrlTree(['/team/1']); + + TestBed.overrideProvider( + canMatchTeamSection, {useFactory: canMatchFactory, deps: [Router]}); + + const router = TestBed.inject(Router); + + router.resetConfig([ + {path: 'a', canMatch: [canMatchTeamSection], component: SimpleCmp}, + {path: 'team/:id', component: TeamCmp}, + ]); + const fixture = createRoot(router, RootCmp); + + router.navigateByUrl('/a'); advance(fixture); expect(fixture.nativeElement.innerHTML).toContain('team');