Permalink
Browse files

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

… routes


Closes #12375
  • Loading branch information...
vsavkin committed Oct 20, 2016
1 parent 7221632 commit b74185369f4c59f1a4a666ae87e0ff5b30dfee6e
Showing with 45 additions and 33 deletions.
  1. +11 −20 modules/@angular/router/src/router.ts
  2. +34 −13 modules/@angular/router/test/integration.spec.ts
@@ -764,7 +764,7 @@ export class PreActivation {
});
forEach(
prevChildren,
- (v: any, k: string) => this.deactivateOutletAndItChildren(v, outletMap._outlets[k]));
+ (v: any, k: string) => this.deactiveRouteAndItsChildren(v, outletMap._outlets[k]));
}
traverseRoutes(
@@ -794,14 +794,7 @@ export class PreActivation {
}
} else {
if (curr) {
- // if we had a normal route, we need to deactivate only that outlet.
- if (curr.component) {
- this.deactivateOutletAndItChildren(curr, outlet);
-
- // if we had a componentless route, we need to deactivate everything!
- } else {
- this.deactivateOutletMap(parentOutletMap);
- }
+ this.deactiveRouteAndItsChildren(currNode, outlet);
}
this.checks.push(new CanActivate(futurePath));
@@ -816,19 +809,17 @@ export class PreActivation {
}
}
- private deactivateOutletAndItChildren(route: ActivatedRouteSnapshot, outlet: RouterOutlet): void {
- if (outlet && outlet.isActivated) {
- this.deactivateOutletMap(outlet.outletMap);
- this.checks.push(new CanDeactivate(outlet.component, route));
- }
- }
+ private deactiveRouteAndItsChildren(
+ route: TreeNode<ActivatedRouteSnapshot>, outlet: RouterOutlet): void {
+ const prevChildren: {[key: string]: any} = nodeChildrenAsMap(route);
- private deactivateOutletMap(outletMap: RouterOutletMap): void {
- forEach(outletMap._outlets, (v: RouterOutlet) => {
- if (v.isActivated) {
- this.deactivateOutletAndItChildren(v.activatedRoute.snapshot, v);
- }
+ forEach(prevChildren, (v: any, k: string) => {
+ const childOutlet = outlet ? outlet.outletMap._outlets[k] : null;
+ this.deactiveRouteAndItsChildren(v, childOutlet);
});
+
+ const component = outlet && outlet.isActivated ? outlet.component : null;
+ this.checks.push(new CanDeactivate(component, route.value));
}
private runCanActivate(future: ActivatedRouteSnapshot): Observable<boolean> {
@@ -1055,7 +1055,11 @@ describe('Integration', () => {
describe('CanDeactivate', () => {
describe('should not deactivate a route when CanDeactivate returns false', () => {
+ let log: any;
+
beforeEach(() => {
+ log = [];
+
TestBed.configureTestingModule({
providers: [
{
@@ -1076,6 +1080,13 @@ describe('Integration', () => {
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);
})));
- it('works (componentless route)',
+ it('works with componentless routes',
fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
const fixture = createRoot(router, RootCmp);
- router.resetConfig([{
- path: 'parent/:id',
- canDeactivate: ['CanDeactivateParent'],
- children: [{path: 'simple', component: SimpleCmp}]
- }]);
+ router.resetConfig([
+ {
+ path: 'grandparent',
+ 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);
- 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);
- expect(location.path()).toEqual('/parent/33/simple');
- router.navigateByUrl('/parent/44/simple');
- advance(fixture);
- expect(location.path()).toEqual('/parent/33/simple');
+ expect(log).toEqual([
+ ['Deactivate', 'child'], ['Deactivate', 'parent'], ['Deactivate', 'grandparent']
+ ]);
})));
it('works with a nested route',

0 comments on commit b741853

Please sign in to comment.