Skip to content

Commit

Permalink
feat(router): add initialNavOnly mode for runGuardsAndResolvers
Browse files Browse the repository at this point in the history
This option means guards and resolvers will only run the first
time a particular route is navigated to. Changes to params in
any way will not cause guards and resolvers to re-run. They
will only re-run when changing to a new route.

Related to discussion in angular#18253
FW-560 #resolve
  • Loading branch information
jasonaden committed Oct 30, 2018
1 parent b95089d commit 74fd3a4
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 1 deletion.
4 changes: 3 additions & 1 deletion packages/router/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* - `runGuardsAndResolvers` defines when guards and resolvers will be run. By default they run only
* when the matrix parameters of the route change. When set to `paramsOrQueryParamsChange` they
* will also run when query params change. And when set to `always`, they will run every time.
* When set to `initialNavOnly`, they will run when first loading a route, but ignore changes to
* any type of parameters. This mode is the opposite of `always`.
* - `children` is an array of child route definitions.
* - `loadChildren` is a reference to lazy loaded child routes. See `LoadChildren` for more
* info.
Expand Down Expand Up @@ -359,7 +361,7 @@ export type QueryParamsHandling = 'merge' | 'preserve' | '';
* See `Routes` for more details.
* @publicApi
*/
export type RunGuardsAndResolvers = 'paramsChange' | 'paramsOrQueryParamsChange' | 'always';
export type RunGuardsAndResolvers = 'paramsChange' | 'paramsOrQueryParamsChange' | 'always' | 'initialNavOnly';

/**
* See `Routes` for more details.
Expand Down
3 changes: 3 additions & 0 deletions packages/router/src/utils/preactivation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ function shouldRunGuardsAndResolvers(
curr: ActivatedRouteSnapshot, future: ActivatedRouteSnapshot,
mode: RunGuardsAndResolvers | undefined): boolean {
switch (mode) {
case 'initialNavOnly':
return false;

case 'always':
return true;

Expand Down
33 changes: 33 additions & 0 deletions packages/router/test/integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2148,6 +2148,39 @@ describe('Integration', () => {
expect(guardRunCount).toEqual(5);
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) => {
const fixture = configureRouter(router, 'initialNavOnly');

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}]);

// Subsequent navigations will not run guards and 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}]);

router.navigateByUrl('/a;p=2?q=1');
advance(fixture);
expect(guardRunCount).toEqual(1);
expect(recordedData).toEqual([{data: 0}]);

router.navigateByUrl('/a;p=2(right:b)?q=1');
advance(fixture);
expect(guardRunCount).toEqual(1);
expect(recordedData).toEqual([{data: 0}]);
})));
});

describe('should wait for parent to complete', () => {
Expand Down

0 comments on commit 74fd3a4

Please sign in to comment.