diff --git a/packages/router/src/config.ts b/packages/router/src/config.ts index fcc9c5af27..8f989b5664 100644 --- a/packages/router/src/config.ts +++ b/packages/router/src/config.ts @@ -42,9 +42,11 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree'; * mode ignores query param changes. * - `paramsOrQueryParamsChange` - Guards and resolvers will run when any parameters change. This * includes path, matrix, and query params. - * - `pathParamsChange` Run guards and resolvers path or any path params change. This mode is + * - `pathParamsChange` - Run guards and resolvers path or any path params change. This mode is * useful if you want to ignore changes to all optional parameters such as query *and* matrix * params. + * - `pathParamsOrQueryParamsChange` - Same as `pathParamsChange`, but also rerun when any query + * param changes * - `always` - Run guards and resolvers on every navigation. * - `children` is an array of child route definitions. * - `loadChildren` is a reference to lazy loaded child routes. See `LoadChildren` for more @@ -366,8 +368,8 @@ export type QueryParamsHandling = 'merge' | 'preserve' | ''; * See `Routes` for more details. * @publicApi */ -export type RunGuardsAndResolvers = - 'pathParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always'; +export type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | + 'paramsChange' | 'paramsOrQueryParamsChange' | 'always'; /** * See `Routes` for more details. diff --git a/packages/router/src/utils/preactivation.ts b/packages/router/src/utils/preactivation.ts index e8324b8402..90d3a9bcc8 100644 --- a/packages/router/src/utils/preactivation.ts +++ b/packages/router/src/utils/preactivation.ts @@ -151,6 +151,10 @@ function shouldRunGuardsAndResolvers( case 'pathParamsChange': return !equalPath(curr.url, future.url); + case 'pathParamsOrQueryParamsChange': + return !equalPath(curr.url, future.url) || + !shallowEqual(curr.queryParams, future.queryParams); + case 'always': return true; diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index e411ca12cc..31eddaa061 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -2375,7 +2375,8 @@ describe('Integration', () => { expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}, {data: 3}, {data: 4}]); }))); - it('should not rerun guards and resolvers', fakeAsync(inject([Router], (router: Router) => { + it('should rerun rerun guards and resolvers when path params change', + fakeAsync(inject([Router], (router: Router) => { const fixture = configureRouter(router, 'pathParamsChange'); const cmp: RouteCmp = fixture.debugElement.children[1].componentInstance; @@ -2448,6 +2449,42 @@ describe('Integration', () => { expect(guardRunCount).toEqual(4); }))); + + it('should rerun rerun guards and resolvers when path or query params change', + fakeAsync(inject([Router], (router: Router) => { + const fixture = configureRouter(router, 'pathParamsOrQueryParamsChange'); + + const cmp: RouteCmp = fixture.debugElement.children[1].componentInstance; + const recordedData: any[] = []; + cmp.route.data.subscribe((data: any) => recordedData.push(data)); + + // First navigation has already run + expect(guardRunCount).toEqual(1); + expect(recordedData).toEqual([{data: 0}]); + + // Changing matrix params will not result in running guards or resolvers + router.navigateByUrl('/a;p=1'); + advance(fixture); + expect(guardRunCount).toEqual(1); + expect(recordedData).toEqual([{data: 0}]); + + router.navigateByUrl('/a;p=2'); + advance(fixture); + expect(guardRunCount).toEqual(1); + expect(recordedData).toEqual([{data: 0}]); + + // Adding query params will re-run guards/resolvers + router.navigateByUrl('/a;p=2?q=1'); + advance(fixture); + expect(guardRunCount).toEqual(2); + expect(recordedData).toEqual([{data: 0}, {data: 1}]); + + // Changing query params will re-run guards/resolvers + router.navigateByUrl('/a;p=2?q=2'); + advance(fixture); + expect(guardRunCount).toEqual(3); + expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}]); + }))); }); describe('should wait for parent to complete', () => { diff --git a/tools/public_api_guard/router/router.d.ts b/tools/public_api_guard/router/router.d.ts index 6678230347..49715128e5 100644 --- a/tools/public_api_guard/router/router.d.ts +++ b/tools/public_api_guard/router/router.d.ts @@ -473,7 +473,7 @@ export declare class RoutesRecognized extends RouterEvent { toString(): string; } -export declare type RunGuardsAndResolvers = 'pathParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always'; +export declare type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always'; export declare class Scroll { readonly anchor: string | null;