feat(router): add an extra argument to CanDeactivate interface (#13560)
Adds a `nextState` argument to access the future url from `CanDeactivate`. BEFORE: canDeactivate(component: T, route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean; AFTER: canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean; Closes #9853
This commit is contained in:
parent
445ed43b9a
commit
69fa3bbc03
|
@ -185,8 +185,9 @@ export interface CanActivateChild {
|
||||||
*
|
*
|
||||||
* canDeactivate(
|
* canDeactivate(
|
||||||
* component: TeamComponent,
|
* component: TeamComponent,
|
||||||
* route: ActivatedRouteSnapshot,
|
* currentRoute: ActivatedRouteSnapshot,
|
||||||
* state: RouterStateSnapshot
|
* currentState: RouterStateSnapshot,
|
||||||
|
* nextState: RouterStateSnapshot
|
||||||
* ): Observable<boolean>|Promise<boolean>|boolean {
|
* ): Observable<boolean>|Promise<boolean>|boolean {
|
||||||
* return this.permissions.canDeactivate(this.currentUser, route.params.id);
|
* return this.permissions.canDeactivate(this.currentUser, route.params.id);
|
||||||
* }
|
* }
|
||||||
|
@ -223,7 +224,8 @@ export interface CanActivateChild {
|
||||||
* providers: [
|
* providers: [
|
||||||
* {
|
* {
|
||||||
* provide: 'canDeactivateTeam',
|
* provide: 'canDeactivateTeam',
|
||||||
* useValue: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => true
|
* useValue: (component: TeamComponent, currentRoute: ActivatedRouteSnapshot, currentState:
|
||||||
|
* RouterStateSnapshot, nextState: RouterStateSnapshot) => true
|
||||||
* }
|
* }
|
||||||
* ]
|
* ]
|
||||||
* })
|
* })
|
||||||
|
@ -233,8 +235,9 @@ export interface CanActivateChild {
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export interface CanDeactivate<T> {
|
export interface CanDeactivate<T> {
|
||||||
canDeactivate(component: T, route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
|
canDeactivate(
|
||||||
Observable<boolean>|Promise<boolean>|boolean;
|
component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot,
|
||||||
|
nextState?: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -985,9 +985,10 @@ export class PreActivation {
|
||||||
const guard = this.getToken(c, curr);
|
const guard = this.getToken(c, curr);
|
||||||
let observable: Observable<boolean>;
|
let observable: Observable<boolean>;
|
||||||
if (guard.canDeactivate) {
|
if (guard.canDeactivate) {
|
||||||
observable = wrapIntoObservable(guard.canDeactivate(component, curr, this.curr));
|
observable =
|
||||||
|
wrapIntoObservable(guard.canDeactivate(component, curr, this.curr, this.future));
|
||||||
} else {
|
} else {
|
||||||
observable = wrapIntoObservable(guard(component, curr, this.curr));
|
observable = wrapIntoObservable(guard(component, curr, this.curr, this.future));
|
||||||
}
|
}
|
||||||
return first.call(observable);
|
return first.call(observable);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1647,6 +1647,69 @@ describe('Integration', () => {
|
||||||
expect(location.path()).toEqual('/simple');
|
expect(location.path()).toEqual('/simple');
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
describe('next state', () => {
|
||||||
|
let log: string[];
|
||||||
|
|
||||||
|
class ClassWithNextState implements CanDeactivate<TeamCmp> {
|
||||||
|
canDeactivate(
|
||||||
|
component: TeamCmp, currentRoute: ActivatedRouteSnapshot,
|
||||||
|
currentState: RouterStateSnapshot, nextState: RouterStateSnapshot): boolean {
|
||||||
|
log.push(currentState.url, nextState.url);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
log = [];
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
ClassWithNextState, {
|
||||||
|
provide: 'FunctionWithNextState',
|
||||||
|
useValue: (cmp: any, currentRoute: ActivatedRouteSnapshot,
|
||||||
|
currentState: RouterStateSnapshot, nextState: RouterStateSnapshot) => {
|
||||||
|
log.push(currentState.url, nextState.url);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass next state as the 4 argument when guard is a class',
|
||||||
|
fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
||||||
|
const fixture = createRoot(router, RootCmp);
|
||||||
|
|
||||||
|
router.resetConfig(
|
||||||
|
[{path: 'team/:id', component: TeamCmp, canDeactivate: [ClassWithNextState]}]);
|
||||||
|
|
||||||
|
router.navigateByUrl('/team/22');
|
||||||
|
advance(fixture);
|
||||||
|
expect(location.path()).toEqual('/team/22');
|
||||||
|
|
||||||
|
router.navigateByUrl('/team/33');
|
||||||
|
advance(fixture);
|
||||||
|
expect(location.path()).toEqual('/team/33');
|
||||||
|
expect(log).toEqual(['/team/22', '/team/33']);
|
||||||
|
})));
|
||||||
|
|
||||||
|
it('should pass next state as the 4 argument when guard is a function',
|
||||||
|
fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
||||||
|
const fixture = createRoot(router, RootCmp);
|
||||||
|
|
||||||
|
router.resetConfig([
|
||||||
|
{path: 'team/:id', component: TeamCmp, canDeactivate: ['FunctionWithNextState']}
|
||||||
|
]);
|
||||||
|
|
||||||
|
router.navigateByUrl('/team/22');
|
||||||
|
advance(fixture);
|
||||||
|
expect(location.path()).toEqual('/team/22');
|
||||||
|
|
||||||
|
router.navigateByUrl('/team/33');
|
||||||
|
advance(fixture);
|
||||||
|
expect(location.path()).toEqual('/team/33');
|
||||||
|
expect(log).toEqual(['/team/22', '/team/33']);
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
|
||||||
describe('should work when given a class', () => {
|
describe('should work when given a class', () => {
|
||||||
class AlwaysTrue implements CanDeactivate<TeamCmp> {
|
class AlwaysTrue implements CanDeactivate<TeamCmp> {
|
||||||
|
|
|
@ -47,7 +47,7 @@ export interface CanActivateChild {
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export interface CanDeactivate<T> {
|
export interface CanDeactivate<T> {
|
||||||
canDeactivate(component: T, route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean;
|
canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
|
|
Loading…
Reference in New Issue