fix(router): canDeactivate guards are not triggered for componentless routes

Closes #12375
This commit is contained in:
vsavkin 2016-10-20 13:32:38 -07:00
parent 7221632228
commit b74185369f
2 changed files with 45 additions and 33 deletions

View File

@ -764,7 +764,7 @@ export class PreActivation {
}); });
forEach( forEach(
prevChildren, prevChildren,
(v: any, k: string) => this.deactivateOutletAndItChildren(v, outletMap._outlets[k])); (v: any, k: string) => this.deactiveRouteAndItsChildren(v, outletMap._outlets[k]));
} }
traverseRoutes( traverseRoutes(
@ -794,14 +794,7 @@ export class PreActivation {
} }
} else { } else {
if (curr) { if (curr) {
// if we had a normal route, we need to deactivate only that outlet. this.deactiveRouteAndItsChildren(currNode, outlet);
if (curr.component) {
this.deactivateOutletAndItChildren(curr, outlet);
// if we had a componentless route, we need to deactivate everything!
} else {
this.deactivateOutletMap(parentOutletMap);
}
} }
this.checks.push(new CanActivate(futurePath)); this.checks.push(new CanActivate(futurePath));
@ -816,19 +809,17 @@ export class PreActivation {
} }
} }
private deactivateOutletAndItChildren(route: ActivatedRouteSnapshot, outlet: RouterOutlet): void { private deactiveRouteAndItsChildren(
if (outlet && outlet.isActivated) { route: TreeNode<ActivatedRouteSnapshot>, outlet: RouterOutlet): void {
this.deactivateOutletMap(outlet.outletMap); const prevChildren: {[key: string]: any} = nodeChildrenAsMap(route);
this.checks.push(new CanDeactivate(outlet.component, route));
}
}
private deactivateOutletMap(outletMap: RouterOutletMap): void { forEach(prevChildren, (v: any, k: string) => {
forEach(outletMap._outlets, (v: RouterOutlet) => { const childOutlet = outlet ? outlet.outletMap._outlets[k] : null;
if (v.isActivated) { this.deactiveRouteAndItsChildren(v, childOutlet);
this.deactivateOutletAndItChildren(v.activatedRoute.snapshot, v);
}
}); });
const component = outlet && outlet.isActivated ? outlet.component : null;
this.checks.push(new CanDeactivate(component, route.value));
} }
private runCanActivate(future: ActivatedRouteSnapshot): Observable<boolean> { private runCanActivate(future: ActivatedRouteSnapshot): Observable<boolean> {

View File

@ -1055,7 +1055,11 @@ describe('Integration', () => {
describe('CanDeactivate', () => { describe('CanDeactivate', () => {
describe('should not deactivate a route when CanDeactivate returns false', () => { describe('should not deactivate a route when CanDeactivate returns false', () => {
let log: any;
beforeEach(() => { beforeEach(() => {
log = [];
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [ providers: [
{ {
@ -1076,6 +1080,13 @@ describe('Integration', () => {
return a.params['name'] === 'victor'; return a.params['name'] === 'victor';
} }
}, },
{
provide: 'RecordingDeactivate',
useValue: (c: any, a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => {
log.push(['Deactivate', a.routeConfig.path]);
return true;
}
},
] ]
}); });
}); });
@ -1103,27 +1114,37 @@ describe('Integration', () => {
expect(canceledStatus).toEqual(false); expect(canceledStatus).toEqual(false);
}))); })));
it('works (componentless route)', it('works with componentless routes',
fakeAsync(inject([Router, Location], (router: Router, location: Location) => { fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
const fixture = createRoot(router, RootCmp); const fixture = createRoot(router, RootCmp);
router.resetConfig([{ router.resetConfig([
path: 'parent/:id', {
canDeactivate: ['CanDeactivateParent'], path: 'grandparent',
children: [{path: 'simple', component: SimpleCmp}] canDeactivate: ['RecordingDeactivate'],
}]); children: [{
path: 'parent',
canDeactivate: ['RecordingDeactivate'],
children: [{
path: 'child',
canDeactivate: ['RecordingDeactivate'],
children: [{path: 'simple', component: SimpleCmp}]
}]
}]
},
{path: 'simple', component: SimpleCmp}
]);
router.navigateByUrl('/parent/22/simple'); router.navigateByUrl('/grandparent/parent/child/simple');
advance(fixture); advance(fixture);
expect(location.path()).toEqual('/parent/22/simple'); expect(location.path()).toEqual('/grandparent/parent/child/simple');
router.navigateByUrl('/parent/33/simple'); router.navigateByUrl('/simple');
advance(fixture); advance(fixture);
expect(location.path()).toEqual('/parent/33/simple');
router.navigateByUrl('/parent/44/simple'); expect(log).toEqual([
advance(fixture); ['Deactivate', 'child'], ['Deactivate', 'parent'], ['Deactivate', 'grandparent']
expect(location.path()).toEqual('/parent/33/simple'); ]);
}))); })));
it('works with a nested route', it('works with a nested route',