feat(router): add predicate function mode for runGuardsAndResolvers (#27682)
This option means guards and resolvers will ignore changes when a provided predicate function returns `false`. This supports use cases where an application needs to ignore some param updates but not others. For example, changing a sort param in the URL might need to be ignored, whereas changing the a `project` param might require re-run of guards and resolvers. Related to #26861 #18253 #27464 PR Close #27682
This commit is contained in:
parent
7901cd8cfb
commit
12c317603a
|
@ -8,10 +8,13 @@
|
||||||
|
|
||||||
import {NgModuleFactory, NgModuleRef, Type} from '@angular/core';
|
import {NgModuleFactory, NgModuleRef, Type} from '@angular/core';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
|
|
||||||
import {EmptyOutletComponent} from './components/empty_outlet';
|
import {EmptyOutletComponent} from './components/empty_outlet';
|
||||||
|
import {ActivatedRouteSnapshot} from './router_state';
|
||||||
import {PRIMARY_OUTLET} from './shared';
|
import {PRIMARY_OUTLET} from './shared';
|
||||||
import {UrlSegment, UrlSegmentGroup} from './url_tree';
|
import {UrlSegment, UrlSegmentGroup} from './url_tree';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
|
@ -48,6 +51,10 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
|
||||||
* - `pathParamsOrQueryParamsChange` - Same as `pathParamsChange`, but also rerun when any query
|
* - `pathParamsOrQueryParamsChange` - Same as `pathParamsChange`, but also rerun when any query
|
||||||
* param changes
|
* param changes
|
||||||
* - `always` - Run guards and resolvers on every navigation.
|
* - `always` - Run guards and resolvers on every navigation.
|
||||||
|
* - (from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean - Use a predicate
|
||||||
|
* function when none of the pre-configured modes fit the needs of the application. An example
|
||||||
|
* might be when you need to ignore updates to a param such as `sortDirection`, but need to
|
||||||
|
* reload guards and resolvers when changing the `searchRoot` param.
|
||||||
* - `children` is an array of child route definitions.
|
* - `children` is an array of child route definitions.
|
||||||
* - `loadChildren` is a reference to lazy loaded child routes. See `LoadChildren` for more
|
* - `loadChildren` is a reference to lazy loaded child routes. See `LoadChildren` for more
|
||||||
* info.
|
* info.
|
||||||
|
@ -369,7 +376,8 @@ export type QueryParamsHandling = 'merge' | 'preserve' | '';
|
||||||
* @publicApi
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' |
|
export type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' |
|
||||||
'paramsChange' | 'paramsOrQueryParamsChange' | 'always';
|
'paramsChange' | 'paramsOrQueryParamsChange' | 'always' |
|
||||||
|
((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See `Routes` for more details.
|
* See `Routes` for more details.
|
||||||
|
|
|
@ -147,6 +147,9 @@ function getRouteGuards(
|
||||||
function shouldRunGuardsAndResolvers(
|
function shouldRunGuardsAndResolvers(
|
||||||
curr: ActivatedRouteSnapshot, future: ActivatedRouteSnapshot,
|
curr: ActivatedRouteSnapshot, future: ActivatedRouteSnapshot,
|
||||||
mode: RunGuardsAndResolvers | undefined): boolean {
|
mode: RunGuardsAndResolvers | undefined): boolean {
|
||||||
|
if (typeof mode === 'function') {
|
||||||
|
return mode(curr, future);
|
||||||
|
}
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 'pathParamsChange':
|
case 'pathParamsChange':
|
||||||
return !equalPath(curr.url, future.url);
|
return !equalPath(curr.url, future.url);
|
||||||
|
|
|
@ -2487,6 +2487,43 @@ describe('Integration', () => {
|
||||||
expect(guardRunCount).toEqual(3);
|
expect(guardRunCount).toEqual(3);
|
||||||
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}]);
|
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}]);
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
it('should allow a predicate function to determine when to run guards and resolvers',
|
||||||
|
fakeAsync(inject([Router], (router: Router) => {
|
||||||
|
const fixture = configureRouter(router, (from, to) => to.paramMap.get('p') === '2');
|
||||||
|
|
||||||
|
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}]);
|
||||||
|
|
||||||
|
// Adding `p` param shouldn't cause re-run
|
||||||
|
router.navigateByUrl('/a;p=1');
|
||||||
|
advance(fixture);
|
||||||
|
expect(guardRunCount).toEqual(1);
|
||||||
|
expect(recordedData).toEqual([{data: 0}]);
|
||||||
|
|
||||||
|
// Re-run should trigger on p=2
|
||||||
|
router.navigateByUrl('/a;p=2');
|
||||||
|
advance(fixture);
|
||||||
|
expect(guardRunCount).toEqual(2);
|
||||||
|
expect(recordedData).toEqual([{data: 0}, {data: 1}]);
|
||||||
|
|
||||||
|
// Any other changes don't pass the predicate
|
||||||
|
router.navigateByUrl('/a;p=3?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=3?q=2');
|
||||||
|
advance(fixture);
|
||||||
|
expect(guardRunCount).toEqual(2);
|
||||||
|
expect(recordedData).toEqual([{data: 0}, {data: 1}]);
|
||||||
|
})));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should wait for parent to complete', () => {
|
describe('should wait for parent to complete', () => {
|
||||||
|
|
|
@ -473,7 +473,7 @@ export declare class RoutesRecognized extends RouterEvent {
|
||||||
toString(): string;
|
toString(): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always';
|
export declare type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always' | ((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean);
|
||||||
|
|
||||||
export declare class Scroll {
|
export declare class Scroll {
|
||||||
readonly anchor: string | null;
|
readonly anchor: string | null;
|
||||||
|
|
Loading…
Reference in New Issue