From 8f2fa0f766d9f850e13db1e62a1c3f93e090a500 Mon Sep 17 00:00:00 2001 From: vsavkin Date: Thu, 20 Oct 2016 15:00:15 -0700 Subject: [PATCH] fix(router): disallow component routes with named outlets Closes #11208, #11082 --- modules/@angular/router/src/config.ts | 6 +++++- .../@angular/router/src/directives/router_outlet.ts | 6 ++++-- modules/@angular/router/test/config.spec.ts | 11 +++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/modules/@angular/router/src/config.ts b/modules/@angular/router/src/config.ts index bb11339056..619a39119f 100644 --- a/modules/@angular/router/src/config.ts +++ b/modules/@angular/router/src/config.ts @@ -8,7 +8,7 @@ import {Type} from '@angular/core'; import {Observable} from 'rxjs/Observable'; - +import {PRIMARY_OUTLET} from './shared'; /** * @whatItDoes Represents router configuration. @@ -320,6 +320,10 @@ function validateNode(route: Route): void { if (Array.isArray(route)) { throw new Error(`Invalid route configuration: Array cannot be specified`); } + if (route.component === undefined && (route.outlet && route.outlet !== PRIMARY_OUTLET)) { + throw new Error( + `Invalid route configuration of route '${route.path}': a componentless route cannot have a named outlet set`); + } if (!!route.redirectTo && !!route.children) { throw new Error( `Invalid configuration of route '${route.path}': redirectTo and children cannot be used together`); diff --git a/modules/@angular/router/src/directives/router_outlet.ts b/modules/@angular/router/src/directives/router_outlet.ts index e8be3b860a..1ed1706d18 100644 --- a/modules/@angular/router/src/directives/router_outlet.ts +++ b/modules/@angular/router/src/directives/router_outlet.ts @@ -12,8 +12,6 @@ import {RouterOutletMap} from '../router_outlet_map'; import {ActivatedRoute} from '../router_state'; import {PRIMARY_OUTLET} from '../shared'; - - /** * @whatItDoes Acts as a placeholder that Angular dynamically fills based on the current router * state. @@ -79,6 +77,10 @@ export class RouterOutlet implements OnDestroy { activatedRoute: ActivatedRoute, loadedResolver: ComponentFactoryResolver, loadedInjector: Injector, providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap): void { + if (this.isActivated) { + throw new Error('Cannot activate an already activated outlet'); + } + this.outletMap = outletMap; this._activatedRoute = activatedRoute; diff --git a/modules/@angular/router/test/config.spec.ts b/modules/@angular/router/test/config.spec.ts index f54923fb48..e08db82cbd 100644 --- a/modules/@angular/router/test/config.spec.ts +++ b/modules/@angular/router/test/config.spec.ts @@ -7,6 +7,7 @@ */ import {validateConfig} from '../src/config'; +import {PRIMARY_OUTLET} from '../src/shared'; describe('config', () => { describe('validateConfig', () => { @@ -80,6 +81,16 @@ describe('config', () => { .toThrowError( /Invalid configuration of route 'a': pathMatch can only be set to 'prefix' or 'full'/); }); + + it('should throw when pathPatch is invalid', () => { + expect(() => { validateConfig([{path: 'a', outlet: 'aux', children: []}]); }) + .toThrowError( + /Invalid route configuration of route 'a': a componentless route cannot have a named outlet set/); + + expect(() => validateConfig([{path: 'a', outlet: '', children: []}])).not.toThrow(); + expect(() => validateConfig([{path: 'a', outlet: PRIMARY_OUTLET, children: []}])) + .not.toThrow(); + }); }); });