From 193792c27fd87ac236690d2c11d362171fb9b3b0 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Thu, 3 Sep 2015 12:55:08 -0700 Subject: [PATCH] refactor(router): Switch from using APP_COMPONENT binding to a manual ROUTER_PRIMARY_COMPONENT binding. With the coming bootstrapping changes, a single application (and thus Router) can have multiple root components. One of these needs to be identified as the "primary" component from which the Router will load its configuration. This is now done by providing a ROUTER_PRIMARY_COMPONENT binding to the primary component type. --- modules/angular2/router.ts | 28 ++++++++++++------- modules/angular2/src/router/router.ts | 7 ++--- .../integration/router_integration_spec.ts | 14 ++++++---- .../angular2/test/router/route_config_spec.ts | 20 +++++++++---- modules/examples/src/routing/index.ts | 5 ++-- 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/modules/angular2/router.ts b/modules/angular2/router.ts index 47aef7ff3d..19a2913e3a 100644 --- a/modules/angular2/router.ts +++ b/modules/angular2/router.ts @@ -4,7 +4,6 @@ * Maps application URLs into application states, to support deep-linking and navigation. */ - export {Router, RootRouter} from './src/router/router'; export {RouterOutlet} from './src/router/router_outlet'; export {RouterLink} from './src/router/router_link'; @@ -30,9 +29,11 @@ import {RouterOutlet} from './src/router/router_outlet'; import {RouterLink} from './src/router/router_link'; import {RouteRegistry} from './src/router/route_registry'; import {Location} from './src/router/location'; -import {APP_COMPONENT} from './src/core/application_tokens'; -import {Binding} from './core'; -import {CONST_EXPR} from './src/core/facade/lang'; +import {bind, OpaqueToken, Binding} from './core'; +import {CONST_EXPR, Type} from './src/core/facade/lang'; + +export const ROUTER_PRIMARY_COMPONENT: OpaqueToken = + CONST_EXPR(new OpaqueToken('RouterPrimaryComponent')); export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]); @@ -55,18 +56,25 @@ export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]); * } * * - * bootstrap(AppCmp, [ROUTER_BINDINGS]); + * bootstrap(AppCmp, [routerBindings(AppCmp)]); * ``` */ export const ROUTER_BINDINGS: any[] = CONST_EXPR([ RouteRegistry, CONST_EXPR(new Binding(LocationStrategy, {toClass: PathLocationStrategy})), Location, - CONST_EXPR(new Binding( - Router, - {toFactory: routerFactory, deps: CONST_EXPR([RouteRegistry, Location, APP_COMPONENT])})) + CONST_EXPR( + new Binding(Router, + { + toFactory: routerFactory, + deps: CONST_EXPR([RouteRegistry, Location, ROUTER_PRIMARY_COMPONENT]) + })) ]); -function routerFactory(registry, location, appRoot) { - return new RootRouter(registry, location, appRoot); +function routerFactory(registry, location, primaryComponent) { + return new RootRouter(registry, location, primaryComponent); +} + +export function routerBindings(primaryComponent: Type): Array { + return [ROUTER_BINDINGS, bind(ROUTER_PRIMARY_COMPONENT).toValue(primaryComponent)]; } diff --git a/modules/angular2/src/router/router.ts b/modules/angular2/src/router/router.ts index 1b49199798..20a55d287f 100644 --- a/modules/angular2/src/router/router.ts +++ b/modules/angular2/src/router/router.ts @@ -457,13 +457,12 @@ export class Router { export class RootRouter extends Router { _location: Location; - constructor(registry: RouteRegistry, location: Location, hostComponent: Type) { - super(registry, null, hostComponent); + constructor(registry: RouteRegistry, location: Location, primaryComponent: Type) { + super(registry, null, primaryComponent); this._location = location; this._location.subscribe((change) => this.navigateByUrl(change['url'], isPresent(change['pop']))); - - this.registry.configFromComponent(hostComponent); + this.registry.configFromComponent(primaryComponent); this.navigateByUrl(location.path()); } diff --git a/modules/angular2/test/router/integration/router_integration_spec.ts b/modules/angular2/test/router/integration/router_integration_spec.ts index 7b44ef8452..61a5e4893b 100644 --- a/modules/angular2/test/router/integration/router_integration_spec.ts +++ b/modules/angular2/test/router/integration/router_integration_spec.ts @@ -24,6 +24,7 @@ import {PromiseWrapper} from 'angular2/src/core/facade/async'; import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions'; import { ROUTER_BINDINGS, + ROUTER_PRIMARY_COMPONENT, RouteParams, Router, APP_BASE_HREF, @@ -33,7 +34,6 @@ import { import {LocationStrategy} from 'angular2/src/router/location_strategy'; import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy'; -import {APP_COMPONENT} from 'angular2/src/core/application_tokens'; export function main() { describe('router injectables', () => { @@ -51,6 +51,7 @@ export function main() { bootstrap(AppCmp, [ ROUTER_BINDINGS, + bind(ROUTER_PRIMARY_COMPONENT).toValue(AppCmp), bind(LocationStrategy).toClass(MockLocationStrategy), bind(DOCUMENT).toValue(fakeDoc) ]) @@ -66,7 +67,7 @@ export function main() { }); describe('broken app', () => { - beforeEachBindings(() => { return [bind(APP_COMPONENT).toValue(BrokenAppCmp)]; }); + beforeEachBindings(() => { return [bind(ROUTER_PRIMARY_COMPONENT).toValue(BrokenAppCmp)]; }); it('should rethrow exceptions from component constructors', inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => { @@ -82,7 +83,8 @@ export function main() { }); describe('back button app', () => { - beforeEachBindings(() => { return [bind(APP_COMPONENT).toValue(HierarchyAppCmp)]; }); + beforeEachBindings( + () => { return [bind(ROUTER_PRIMARY_COMPONENT).toValue(HierarchyAppCmp)]; }); it('should change the url without pushing a new history state for back navigations', inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => { @@ -133,7 +135,8 @@ export function main() { }); describe('hierarchical app', () => { - beforeEachBindings(() => { return [bind(APP_COMPONENT).toValue(HierarchyAppCmp)]; }); + beforeEachBindings( + () => { return [bind(ROUTER_PRIMARY_COMPONENT).toValue(HierarchyAppCmp)]; }); it('should bootstrap an app with a hierarchy', inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => { @@ -177,7 +180,8 @@ export function main() { // TODO: add a test in which the child component has bindings describe('querystring params app', () => { - beforeEachBindings(() => { return [bind(APP_COMPONENT).toValue(QueryStringAppCmp)]; }); + beforeEachBindings( + () => { return [bind(ROUTER_PRIMARY_COMPONENT).toValue(QueryStringAppCmp)]; }); it('should recognize and return querystring params with the injected RouteParams', inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => { diff --git a/modules/angular2/test/router/route_config_spec.ts b/modules/angular2/test/router/route_config_spec.ts index 91c8947f91..5a5c3af8cf 100644 --- a/modules/angular2/test/router/route_config_spec.ts +++ b/modules/angular2/test/router/route_config_spec.ts @@ -20,6 +20,7 @@ import {Type} from 'angular2/src/core/facade/lang'; import { ROUTER_BINDINGS, + ROUTER_PRIMARY_COMPONENT, Router, RouteConfig, APP_BASE_HREF, @@ -56,7 +57,8 @@ export function main() { }); it('should bootstrap an app with a hierarchy', inject([AsyncTestCompleter], (async) => { - bootstrap(HierarchyAppCmp, testBindings) + bootstrap(HierarchyAppCmp, + [bind(ROUTER_PRIMARY_COMPONENT).toValue(HierarchyAppCmp), testBindings]) .then((applicationRef) => { var router = applicationRef.hostComponent.router; router.subscribe((_) => { @@ -70,7 +72,8 @@ export function main() { it('should work in an app with redirects', inject([AsyncTestCompleter], (async) => { - bootstrap(RedirectAppCmp, testBindings) + bootstrap(RedirectAppCmp, + [bind(ROUTER_PRIMARY_COMPONENT).toValue(RedirectAppCmp), testBindings]) .then((applicationRef) => { var router = applicationRef.hostComponent.router; router.subscribe((_) => { @@ -84,7 +87,7 @@ export function main() { it('should work in an app with async components', inject([AsyncTestCompleter], (async) => { - bootstrap(AsyncAppCmp, testBindings) + bootstrap(AsyncAppCmp, [bind(ROUTER_PRIMARY_COMPONENT).toValue(AsyncAppCmp), testBindings]) .then((applicationRef) => { var router = applicationRef.hostComponent.router; router.subscribe((_) => { @@ -99,7 +102,9 @@ export function main() { it('should work in an app with a constructor component', inject([AsyncTestCompleter], (async) => { - bootstrap(ExplicitConstructorAppCmp, testBindings) + bootstrap( + ExplicitConstructorAppCmp, + [bind(ROUTER_PRIMARY_COMPONENT).toValue(ExplicitConstructorAppCmp), testBindings]) .then((applicationRef) => { var router = applicationRef.hostComponent.router; router.subscribe((_) => { @@ -115,7 +120,8 @@ export function main() { inject( [AsyncTestCompleter], (async) => { - bootstrap(WrongConfigCmp, testBindings) + bootstrap(WrongConfigCmp, + [bind(ROUTER_PRIMARY_COMPONENT).toValue(WrongConfigCmp), testBindings]) .catch((e) => { expect(e.originalException) .toContainError( @@ -128,7 +134,9 @@ export function main() { inject( [AsyncTestCompleter], (async) => { - bootstrap(WrongComponentTypeCmp, testBindings) + bootstrap( + WrongComponentTypeCmp, + [bind(ROUTER_PRIMARY_COMPONENT).toValue(WrongComponentTypeCmp), testBindings]) .catch((e) => { expect(e.originalException) .toContainError( diff --git a/modules/examples/src/routing/index.ts b/modules/examples/src/routing/index.ts index 11fbecb0dc..a7a86a4ef1 100644 --- a/modules/examples/src/routing/index.ts +++ b/modules/examples/src/routing/index.ts @@ -1,12 +1,13 @@ import {InboxApp} from './inbox-app'; import {bind} from 'angular2/angular2'; import {bootstrap} from 'angular2/bootstrap'; -import {ROUTER_BINDINGS, HashLocationStrategy, LocationStrategy} from 'angular2/router'; +import {routerBindings, HashLocationStrategy, LocationStrategy} from 'angular2/router'; import {reflector} from 'angular2/src/core/reflection/reflection'; import {ReflectionCapabilities} from 'angular2/src/core/reflection/reflection_capabilities'; export function main() { reflector.reflectionCapabilities = new ReflectionCapabilities(); - bootstrap(InboxApp, [ROUTER_BINDINGS, bind(LocationStrategy).toClass(HashLocationStrategy)]); + bootstrap(InboxApp, + [routerBindings(InboxApp), bind(LocationStrategy).toClass(HashLocationStrategy)]); }