diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts index 1f1c01bcdb..b06949ef5d 100644 --- a/modules/@angular/router/src/router.ts +++ b/modules/@angular/router/src/router.ts @@ -30,11 +30,11 @@ import {RouterOutlet} from './directives/router_outlet'; import {recognize} from './recognize'; import {LoadedRouterConfig, RouterConfigLoader} from './router_config_loader'; import {RouterOutletMap} from './router_outlet_map'; -import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState, inheritedParamsDataResolve} from './router_state'; +import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState, equalParamsAndUrlSegments, inheritedParamsDataResolve} from './router_state'; import {NavigationCancelingError, PRIMARY_OUTLET, Params} from './shared'; import {DefaultUrlHandlingStrategy, UrlHandlingStrategy} from './url_handling_strategy'; import {UrlSerializer, UrlTree, containsTree, createEmptyUrlTree} from './url_tree'; -import {andObservables, forEach, merge, shallowEqual, waitForMap, wrapIntoObservable} from './utils/collection'; +import {andObservables, forEach, merge, waitForMap, wrapIntoObservable} from './utils/collection'; import {TreeNode} from './utils/tree'; declare var Zone: any; @@ -830,7 +830,7 @@ export class PreActivation { // reusing the node if (curr && future._routeConfig === curr._routeConfig) { - if (!shallowEqual(future.params, curr.params)) { + if (!equalParamsAndUrlSegments(future, curr)) { this.checks.push(new CanDeactivate(outlet.component, curr), new CanActivate(futurePath)); } else { // we need to set the data diff --git a/modules/@angular/router/src/router_preloader.ts b/modules/@angular/router/src/router_preloader.ts index 41854ba305..0ef72be73b 100644 --- a/modules/@angular/router/src/router_preloader.ts +++ b/modules/@angular/router/src/router_preloader.ts @@ -83,8 +83,7 @@ export class RouterPreloader { setUpPreloading(): void { const navigations = filter.call(this.router.events, (e: any) => e instanceof NavigationEnd); - this.subscription = - concatMap.call(navigations, () => this.preload()).subscribe((v: any) => {}); + this.subscription = concatMap.call(navigations, () => this.preload()).subscribe((v: any) => {}); } preload(): Observable { return this.processRoutes(this.injector, this.router.config); } diff --git a/modules/@angular/router/src/router_state.ts b/modules/@angular/router/src/router_state.ts index c704ffd3e1..832c1fc0f9 100644 --- a/modules/@angular/router/src/router_state.ts +++ b/modules/@angular/router/src/router_state.ts @@ -12,7 +12,7 @@ import {Observable} from 'rxjs/Observable'; import {Data, ResolveData, Route} from './config'; import {PRIMARY_OUTLET, Params} from './shared'; -import {UrlSegment, UrlSegmentGroup, UrlTree} from './url_tree'; +import {UrlSegment, UrlSegmentGroup, UrlTree, equalSegments} from './url_tree'; import {merge, shallowEqual, shallowEqualArrays} from './utils/collection'; import {Tree, TreeNode} from './utils/tree'; @@ -448,3 +448,9 @@ export function advanceActivatedRoute(route: ActivatedRoute): void { (route.data).next(route._futureSnapshot.data); } } + + +export function equalParamsAndUrlSegments( + a: ActivatedRouteSnapshot, b: ActivatedRouteSnapshot): boolean { + return shallowEqual(a.params, b.params) && equalSegments(a.url, b.url); +} \ No newline at end of file diff --git a/modules/@angular/router/test/integration.spec.ts b/modules/@angular/router/test/integration.spec.ts index 1e38866d31..9a29ec9b95 100644 --- a/modules/@angular/router/test/integration.spec.ts +++ b/modules/@angular/router/test/integration.spec.ts @@ -41,7 +41,7 @@ describe('Integration', () => { expect(location.path()).toEqual('/simple'); }))); - describe('should execute navigations serialy', () => { + describe('should execute navigations serially', () => { let log: any[] = []; beforeEach(() => { @@ -693,6 +693,7 @@ describe('Integration', () => { {provide: 'resolveFour', useValue: (a: any, b: any) => 4}, {provide: 'resolveSix', useClass: ResolveSix}, {provide: 'resolveError', useValue: (a: any, b: any) => Promise.reject('error')}, + {provide: 'numberOfUrlSegments', useValue: (a: any, b: any) => a.url.length} ] }); }); @@ -787,6 +788,29 @@ describe('Integration', () => { const cmp = fixture.debugElement.children[1].componentInstance; expect(cmp.route.snapshot.data).toEqual({two: 2}); }))); + + it('should rerun resolvers when the urls segments of a wildcard route change', + fakeAsync(inject([Router, Location], (router: Router, location: Location) => { + const fixture = createRoot(router, RootCmp); + + router.resetConfig([{ + path: '**', + component: CollectParamsCmp, + resolve: {numberOfUrlSegments: 'numberOfUrlSegments'} + }]); + + let e: any = null; + router.navigateByUrl('/one/two'); + advance(fixture); + const cmp = fixture.debugElement.children[1].componentInstance; + + expect(cmp.route.snapshot.data).toEqual({numberOfUrlSegments: 2}); + + router.navigateByUrl('/one/two/three'); + advance(fixture); + + expect(cmp.route.snapshot.data).toEqual({numberOfUrlSegments: 3}); + }))); }); describe('router links', () => { diff --git a/modules/@angular/router/test/router.spec.ts b/modules/@angular/router/test/router.spec.ts index 27a959770f..6b68809309 100644 --- a/modules/@angular/router/test/router.spec.ts +++ b/modules/@angular/router/test/router.spec.ts @@ -95,6 +95,6 @@ function checkResolveData( function createActivatedRouteSnapshot(cmp: string, extra: any = {}): ActivatedRouteSnapshot { return new ActivatedRouteSnapshot( - null, {}, null, null, null, null, cmp, null, null, -1, + [], {}, null, null, null, null, cmp, null, null, -1, extra.resolve); } \ No newline at end of file diff --git a/modules/@angular/router/test/router_state.spec.ts b/modules/@angular/router/test/router_state.spec.ts index c7c4e5fd1d..ec9677c2fd 100644 --- a/modules/@angular/router/test/router_state.spec.ts +++ b/modules/@angular/router/test/router_state.spec.ts @@ -6,7 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from '../src/router_state'; +import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, equalParamsAndUrlSegments} from '../src/router_state'; +import {Params} from '../src/shared'; +import {UrlSegment} from '../src/url_tree'; import {TreeNode} from '../src/utils/tree'; describe('RouterState & Snapshot', () => { @@ -93,6 +95,33 @@ describe('RouterState & Snapshot', () => { expect(p[1]).toBe(b); }); }); + + describe('equalParamsAndUrlSegments', () => { + function createSnapshot(params: Params, url: UrlSegment[]): ActivatedRouteSnapshot { + return new ActivatedRouteSnapshot( + url, params, null, null, null, null, null, null, null, + -1, null); + } + + it('should return false when params are different', () => { + expect(equalParamsAndUrlSegments(createSnapshot({a: 1}, []), createSnapshot({a: 2}, []))) + .toEqual(false); + }); + + it('should return false when urls are different', () => { + expect(equalParamsAndUrlSegments( + createSnapshot({a: 1}, [new UrlSegment('a', {})]), + createSnapshot({a: 1}, [new UrlSegment('b', {})]))) + .toEqual(false); + }); + + it('should return true othewise', () => { + expect(equalParamsAndUrlSegments( + createSnapshot({a: 1}, [new UrlSegment('a', {})]), + createSnapshot({a: 1}, [new UrlSegment('a', {})]))) + .toEqual(true); + }); + }); }); function createActivatedRouteSnapshot(cmp: string) {