From 97cf0e40d5d11f6e3a79d7f84861281a22b368a0 Mon Sep 17 00:00:00 2001 From: Mike Ryan Date: Wed, 8 Jun 2016 11:23:23 -0700 Subject: [PATCH] fix(guards): Cancel in-flight guards if one returns false --- .../router/src/directives/router_outlet.ts | 6 +- modules/@angular/router/src/router.ts | 68 +++++++++++-------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/modules/@angular/router/src/directives/router_outlet.ts b/modules/@angular/router/src/directives/router_outlet.ts index 99eb1daea6..ae2b742c8e 100644 --- a/modules/@angular/router/src/directives/router_outlet.ts +++ b/modules/@angular/router/src/directives/router_outlet.ts @@ -1,6 +1,6 @@ -import {Attribute, ComponentFactory, ComponentRef, Directive, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from "@angular/core"; -import {RouterOutletMap} from "../router_outlet_map"; -import {PRIMARY_OUTLET} from "../shared"; +import {Attribute, ComponentFactory, ComponentRef, Directive, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core'; +import {RouterOutletMap} from '../router_outlet_map'; +import {PRIMARY_OUTLET} from '../shared'; @Directive({selector: 'router-outlet'}) export class RouterOutlet { diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts index c629188574..6bb67bbba0 100644 --- a/modules/@angular/router/src/router.ts +++ b/modules/@angular/router/src/router.ts @@ -3,13 +3,15 @@ import 'rxjs/add/operator/scan'; import 'rxjs/add/operator/mergeMap'; import 'rxjs/add/operator/concat'; import 'rxjs/add/operator/concatMap'; +import 'rxjs/add/operator/every'; +import 'rxjs/add/operator/mergeAll'; +import 'rxjs/add/observable/from'; import {Location} from '@angular/common'; import {ComponentResolver, Injector, ReflectiveInjector, Type} from '@angular/core'; import {Observable} from 'rxjs/Observable'; import {Subject} from 'rxjs/Subject'; import {Subscription} from 'rxjs/Subscription'; -import {forkJoin} from 'rxjs/observable/forkJoin'; import {of } from 'rxjs/observable/of'; import {RouterConfig} from './config'; @@ -23,7 +25,7 @@ import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot import {PRIMARY_OUTLET, Params} from './shared'; import {UrlSerializer} from './url_serializer'; import {UrlTree, createEmptyUrlTree} from './url_tree'; -import {and, forEach, shallowEqual} from './utils/collection'; +import {forEach, shallowEqual} from './utils/collection'; import {TreeNode} from './utils/tree'; export interface NavigationExtras { @@ -298,16 +300,18 @@ class GuardChecks { const currRoot = this.curr ? this.curr._root : null; this.traverseChildRoutes(futureRoot, currRoot, parentOutletMap); if (this.checks.length === 0) return of (true); - return forkJoin(this.checks.map(s => { - if (s instanceof CanActivate) { - return this.runCanActivate(s.route); - } else if (s instanceof CanDeactivate) { - return this.runCanDeactivate(s.component, s.route); - } else { - throw new Error('Cannot be reached'); - } - })) - .map(and); + return Observable.from(this.checks) + .map(s => { + if (s instanceof CanActivate) { + return this.runCanActivate(s.route); + } else if (s instanceof CanDeactivate) { + return this.runCanDeactivate(s.component, s.route); + } else { + throw new Error('Cannot be reached'); + } + }) + .mergeAll() + .every(result => result === true); } private traverseChildRoutes( @@ -352,29 +356,33 @@ class GuardChecks { private runCanActivate(future: ActivatedRouteSnapshot): Observable { const canActivate = future._routeConfig ? future._routeConfig.canActivate : null; if (!canActivate || canActivate.length === 0) return of (true); - return forkJoin(canActivate.map(c => { - const guard = this.injector.get(c); - if (guard.canActivate) { - return wrapIntoObservable(guard.canActivate(future, this.future)); - } else { - return wrapIntoObservable(guard(future, this.future)); - } - })) - .map(and); + return Observable.from(canActivate) + .map(c => { + const guard = this.injector.get(c); + if (guard.canActivate) { + return wrapIntoObservable(guard.canActivate(future, this.future)); + } else { + return wrapIntoObservable(guard(future, this.future)); + } + }) + .mergeAll() + .every(result => result === true); } private runCanDeactivate(component: Object, curr: ActivatedRouteSnapshot): Observable { const canDeactivate = curr._routeConfig ? curr._routeConfig.canDeactivate : null; if (!canDeactivate || canDeactivate.length === 0) return of (true); - return forkJoin(canDeactivate.map(c => { - const guard = this.injector.get(c); - if (guard.canDeactivate) { - return wrapIntoObservable(guard.canDeactivate(component, curr, this.curr)); - } else { - return wrapIntoObservable(guard(component, curr, this.curr)); - } - })) - .map(and); + return Observable.from(canDeactivate) + .map(c => { + const guard = this.injector.get(c); + if (guard.canDeactivate) { + return wrapIntoObservable(guard.canDeactivate(component, curr, this.curr)); + } else { + return wrapIntoObservable(guard(component, curr, this.curr)); + } + }) + .mergeAll() + .every(result => result === true); } }