diff --git a/modules/angular2/router.ts b/modules/angular2/router.ts index 641794b2da..6304478ebc 100644 --- a/modules/angular2/router.ts +++ b/modules/angular2/router.ts @@ -29,15 +29,15 @@ import {RouterLink} from './src/router/router_link'; import {RouteRegistry} from './src/router/route_registry'; import {Location} from './src/router/location'; import {bind, OpaqueToken, Binding} from './core'; -import {CONST_EXPR, Type} from './src/core/facade/lang'; +import {CONST_EXPR} from './src/core/facade/lang'; +import {ApplicationRef} from './src/core/application_ref'; +import {BaseException} from 'angular2/src/core/facade/exceptions'; + /** * Token used to bind the component with the top-level {@link RouteConfig}s for the * application. * - * You can use the {@link routerBindings} function in your {@link bootstrap} bindings to - * simplify setting up these bindings. - * * ## Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm)) * * ``` @@ -45,7 +45,6 @@ import {CONST_EXPR, Type} from './src/core/facade/lang'; * import { * ROUTER_DIRECTIVES, * ROUTER_BINDINGS, - * ROUTER_PRIMARY_COMPONENT, * RouteConfig * } from 'angular2/router'; * @@ -58,10 +57,7 @@ import {CONST_EXPR, Type} from './src/core/facade/lang'; * // ... * } * - * bootstrap(AppCmp, [ - * ROUTER_BINDINGS, - * bind(ROUTER_PRIMARY_COMPONENT).toValue(AppCmp) - * ]); + * bootstrap(AppCmp, [ROUTER_BINDINGS]); * ``` */ export const ROUTER_PRIMARY_COMPONENT: OpaqueToken = @@ -76,7 +72,7 @@ export const ROUTER_PRIMARY_COMPONENT: OpaqueToken = * * ``` * import {Component, View} from 'angular2/angular2'; - * import {ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router'; + * import {ROUTER_DIRECTIVES, ROUTER_BINDINGS, RouteConfig} from 'angular2/router'; * * @Component({...}) * @View({directives: [ROUTER_DIRECTIVES]}) @@ -87,7 +83,7 @@ export const ROUTER_PRIMARY_COMPONENT: OpaqueToken = * // ... * } * - * bootstrap(AppCmp, [routerBindings(AppCmp)]); + * bootstrap(AppCmp, ROUTER_BINDINGS); * ``` */ export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]); @@ -95,11 +91,6 @@ export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]); /** * A list of {@link Binding}s. To use the router, you must add this to your application. * - * Note that you also need to bind to {@link ROUTER_PRIMARY_COMPONENT}. - * - * You can use the {@link routerBindings} function in your {@link bootstrap} bindings to - * simplify setting up these bindings. - * * ## Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm)) * * ``` @@ -107,7 +98,6 @@ export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]); * import { * ROUTER_DIRECTIVES, * ROUTER_BINDINGS, - * ROUTER_PRIMARY_COMPONENT, * RouteConfig * } from 'angular2/router'; * @@ -120,50 +110,30 @@ export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]); * // ... * } * - * bootstrap(AppCmp, [ - * ROUTER_BINDINGS, - * bind(ROUTER_PRIMARY_COMPONENT).toValue(AppCmp) - * ]); + * bootstrap(AppCmp, [ROUTER_BINDINGS]); * ``` */ 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, ROUTER_PRIMARY_COMPONENT]) - })) + CONST_EXPR(new Binding(Router, + { + toFactory: routerFactory, + deps: CONST_EXPR([RouteRegistry, Location, ROUTER_PRIMARY_COMPONENT]) + })), + CONST_EXPR(new Binding( + ROUTER_PRIMARY_COMPONENT, + {toFactory: routerPrimaryComponentFactory, deps: CONST_EXPR([ApplicationRef])})) ]); function routerFactory(registry, location, primaryComponent) { return new RootRouter(registry, location, primaryComponent); } -/** - * A list of {@link Binding}s. To use the router, you must add these bindings to - * your application. - * - * ## Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm)) - * - * ``` - * import {Component, View} from 'angular2/angular2'; - * import {ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router'; - * - * @Component({...}) - * @View({directives: [ROUTER_DIRECTIVES]}) - * @RouteConfig([ - * {...}, - * ]) - * class AppCmp { - * // ... - * } - * - * bootstrap(AppCmp, [routerBindings(AppCmp)]); - * ``` - */ -export function routerBindings(primaryComponent: Type): Array { - return [ROUTER_BINDINGS, bind(ROUTER_PRIMARY_COMPONENT).toValue(primaryComponent)]; +function routerPrimaryComponentFactory(app) { + if (app.componentTypes.length == 0) { + throw new BaseException("Bootstrap at least one component before injecting Router."); + } + return app.componentTypes[0]; } diff --git a/modules/angular2/src/core/application_ref.ts b/modules/angular2/src/core/application_ref.ts index 3b318fee3a..ae5df71de6 100644 --- a/modules/angular2/src/core/application_ref.ts +++ b/modules/angular2/src/core/application_ref.ts @@ -230,9 +230,10 @@ export class PlatformRef_ extends PlatformRef { private _initApp(zone: NgZone, bindings: Array): ApplicationRef { var injector: Injector; + var app: ApplicationRef; zone.run(() => { bindings.push(bind(NgZone).toValue(zone)); - bindings.push(bind(ApplicationRef).toValue(this)); + bindings.push(bind(ApplicationRef).toFactory((): ApplicationRef => app, [])); var exceptionHandler; try { @@ -247,7 +248,7 @@ export class PlatformRef_ extends PlatformRef { } } }); - var app = new ApplicationRef_(this, zone, injector); + app = new ApplicationRef_(this, zone, injector); this._applications.push(app); return app; } @@ -312,11 +313,17 @@ export abstract class ApplicationRef { * Dispose of this application and all of its components. */ abstract dispose(): void; + + /** + * Get a list of component types registered to this application. + */ + get componentTypes(): Type[] { return unimplemented(); }; } export class ApplicationRef_ extends ApplicationRef { private _bootstrapListeners: Function[] = []; private _rootComponents: ComponentRef[] = []; + private _rootComponentTypes: Type[] = []; constructor(private _platform: PlatformRef_, private _zone: NgZone, private _injector: Injector) { super(); @@ -334,6 +341,7 @@ export class ApplicationRef_ extends ApplicationRef { componentBindings.push(bindings); } var exceptionHandler = this._injector.get(ExceptionHandler); + this._rootComponentTypes.push(componentType); try { var injector: Injector = this._injector.resolveAndCreateChild(componentBindings); var compRefToken: Promise = injector.get(APP_COMPONENT_REF_PROMISE); @@ -369,4 +377,6 @@ export class ApplicationRef_ extends ApplicationRef { this._rootComponents.forEach((ref) => ref.dispose()); this._platform._applicationDisposed(this); } + + get componentTypes(): any[] { return this._rootComponentTypes; } } diff --git a/modules/angular2/src/router/hash_location_strategy.ts b/modules/angular2/src/router/hash_location_strategy.ts index d94e5c81dc..64d0293fd0 100644 --- a/modules/angular2/src/router/hash_location_strategy.ts +++ b/modules/angular2/src/router/hash_location_strategy.ts @@ -18,7 +18,7 @@ import {EventListener, History, Location} from 'angular2/src/core/facade/browser * import {Component, View} from 'angular2/angular2'; * import { * ROUTER_DIRECTIVES, - * routerBindings, + * ROUTER_BINDINGS, * RouteConfig, * Location * } from 'angular2/router'; @@ -34,9 +34,7 @@ import {EventListener, History, Location} from 'angular2/src/core/facade/browser * } * } * - * bootstrap(AppCmp, [ - * routerBindings(AppCmp) - * ]); + * bootstrap(AppCmp, [ROUTER_BINDINGS]); * ``` */ @Injectable() diff --git a/modules/angular2/src/router/instruction.ts b/modules/angular2/src/router/instruction.ts index 21b870025e..6dea78b319 100644 --- a/modules/angular2/src/router/instruction.ts +++ b/modules/angular2/src/router/instruction.ts @@ -16,7 +16,7 @@ import {Url} from './url_parser'; * * ``` * import {bootstrap, Component, View} from 'angular2/angular2'; - * import {Router, ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router'; + * import {Router, ROUTER_DIRECTIVES, ROUTER_BINDINGS, RouteConfig} from 'angular2/router'; * * @Component({...}) * @View({directives: [ROUTER_DIRECTIVES]}) @@ -34,7 +34,7 @@ import {Url} from './url_parser'; * } * } * - * bootstrap(AppCmp, routerBindings(AppCmp)); + * bootstrap(AppCmp, ROUTER_BINDINGS); * ``` */ export class RouteParams { @@ -54,7 +54,7 @@ export class RouteParams { * * ``` * import {bootstrap, Component, View} from 'angular2/angular2'; - * import {Router, ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router'; + * import {Router, ROUTER_DIRECTIVES, ROUTER_BINDINGS, RouteConfig} from 'angular2/router'; * * @Component({...}) * @View({directives: [ROUTER_DIRECTIVES]}) @@ -68,7 +68,7 @@ export class RouteParams { * } * } * - * bootstrap(AppCmp, routerBindings(AppCmp)); + * bootstrap(AppCmp, ROUTER_BINDINGS); * ``` */ export class Instruction { diff --git a/modules/angular2/src/router/location.ts b/modules/angular2/src/router/location.ts index daac5103f1..0fc166b286 100644 --- a/modules/angular2/src/router/location.ts +++ b/modules/angular2/src/router/location.ts @@ -17,7 +17,7 @@ import {OpaqueToken, Injectable, Optional, Inject} from 'angular2/src/core/di'; * * ``` * import {Component, View} from 'angular2/angular2'; - * import {ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router'; + * import {ROUTER_DIRECTIVES, ROUTER_BINDINGS, RouteConfig} from 'angular2/router'; * * @Component({...}) * @View({directives: [ROUTER_DIRECTIVES]}) @@ -29,7 +29,7 @@ import {OpaqueToken, Injectable, Optional, Inject} from 'angular2/src/core/di'; * } * * bootstrap(AppCmp, [ - * routerBindings(AppCmp), + * ROUTER_BINDINGS, * PathLocationStrategy, * bind(APP_BASE_HREF).toValue('/my/app') * ]); @@ -59,7 +59,7 @@ export const APP_BASE_HREF: OpaqueToken = CONST_EXPR(new OpaqueToken('appBaseHre * import {Component, View} from 'angular2/angular2'; * import { * ROUTER_DIRECTIVES, - * routerBindings, + * ROUTER_BINDINGS, * RouteConfig, * Location * } from 'angular2/router'; @@ -75,7 +75,7 @@ export const APP_BASE_HREF: OpaqueToken = CONST_EXPR(new OpaqueToken('appBaseHre * } * } * - * bootstrap(AppCmp, [routerBindings(AppCmp)]); + * bootstrap(AppCmp, [ROUTER_BINDINGS]); * ``` */ @Injectable() diff --git a/modules/angular2/src/router/path_location_strategy.ts b/modules/angular2/src/router/path_location_strategy.ts index f57a8ed5c6..766c62e05a 100644 --- a/modules/angular2/src/router/path_location_strategy.ts +++ b/modules/angular2/src/router/path_location_strategy.ts @@ -10,7 +10,7 @@ import {LocationStrategy} from './location_strategy'; * browser's URL. * * `PathLocationStrategy` is the default binding for {@link LocationStrategy} - * provided in {@link routerBindings} and {@link ROUTER_BINDINGS}. + * provided in {@link ROUTER_BINDINGS}. * * If you're using `PathLocationStrategy`, you must provide a binding for * {@link APP_BASE_HREF} to a string representing the URL prefix that should @@ -27,7 +27,7 @@ import {LocationStrategy} from './location_strategy'; * import { * APP_BASE_HREF * ROUTER_DIRECTIVES, - * routerBindings, + * ROUTER_BINDINGS, * RouteConfig, * Location * } from 'angular2/router'; @@ -44,7 +44,7 @@ import {LocationStrategy} from './location_strategy'; * } * * bootstrap(AppCmp, [ - * routerBindings(AppCmp), // includes binding to PathLocationStrategy + * ROUTER_BINDINGS, // includes binding to PathLocationStrategy * bind(APP_BASE_HREF).toValue('/my/app') * ]); * ``` diff --git a/modules/angular2/test/public_api_spec.ts b/modules/angular2/test/public_api_spec.ts index 2f095e006f..66c3e54e46 100644 --- a/modules/angular2/test/public_api_spec.ts +++ b/modules/angular2/test/public_api_spec.ts @@ -90,6 +90,7 @@ var NG_API = [ 'ApplicationRef:js', 'ApplicationRef.injector:js', 'ApplicationRef.zone:js', + 'ApplicationRef.componentTypes:js', /* Abstract methods 'ApplicationRef.bootstrap()', diff --git a/modules/angular2/test/router/route_config_spec.ts b/modules/angular2/test/router/route_config_spec.ts index a709edc504..2655ba690c 100644 --- a/modules/angular2/test/router/route_config_spec.ts +++ b/modules/angular2/test/router/route_config_spec.ts @@ -20,7 +20,6 @@ import {Type} from 'angular2/src/core/facade/lang'; import { ROUTER_BINDINGS, - ROUTER_PRIMARY_COMPONENT, Router, RouteConfig, APP_BASE_HREF, @@ -57,8 +56,7 @@ export function main() { }); it('should bootstrap an app with a hierarchy', inject([AsyncTestCompleter], (async) => { - bootstrap(HierarchyAppCmp, - [bind(ROUTER_PRIMARY_COMPONENT).toValue(HierarchyAppCmp), testBindings]) + bootstrap(HierarchyAppCmp, testBindings) .then((applicationRef) => { var router = applicationRef.hostComponent.router; router.subscribe((_) => { @@ -72,8 +70,7 @@ export function main() { it('should work in an app with redirects', inject([AsyncTestCompleter], (async) => { - bootstrap(RedirectAppCmp, - [bind(ROUTER_PRIMARY_COMPONENT).toValue(RedirectAppCmp), testBindings]) + bootstrap(RedirectAppCmp, testBindings) .then((applicationRef) => { var router = applicationRef.hostComponent.router; router.subscribe((_) => { @@ -87,7 +84,7 @@ export function main() { it('should work in an app with async components', inject([AsyncTestCompleter], (async) => { - bootstrap(AsyncAppCmp, [bind(ROUTER_PRIMARY_COMPONENT).toValue(AsyncAppCmp), testBindings]) + bootstrap(AsyncAppCmp, testBindings) .then((applicationRef) => { var router = applicationRef.hostComponent.router; router.subscribe((_) => { @@ -102,8 +99,7 @@ export function main() { it('should work in an app with async components defined with "loader"', inject([AsyncTestCompleter], (async) => { - bootstrap(ConciseAsyncAppCmp, - [bind(ROUTER_PRIMARY_COMPONENT).toValue(AsyncAppCmp), testBindings]) + bootstrap(ConciseAsyncAppCmp, testBindings) .then((applicationRef) => { var router = applicationRef.hostComponent.router; router.subscribe((_) => { @@ -118,9 +114,7 @@ export function main() { it('should work in an app with a constructor component', inject([AsyncTestCompleter], (async) => { - bootstrap( - ExplicitConstructorAppCmp, - [bind(ROUTER_PRIMARY_COMPONENT).toValue(ExplicitConstructorAppCmp), testBindings]) + bootstrap(ExplicitConstructorAppCmp, testBindings) .then((applicationRef) => { var router = applicationRef.hostComponent.router; router.subscribe((_) => { @@ -136,8 +130,7 @@ export function main() { inject( [AsyncTestCompleter], (async) => { - bootstrap(WrongConfigCmp, - [bind(ROUTER_PRIMARY_COMPONENT).toValue(WrongConfigCmp), testBindings]) + bootstrap(WrongConfigCmp, testBindings) .catch((e) => { expect(e.originalException) .toContainError( @@ -150,9 +143,7 @@ export function main() { inject( [AsyncTestCompleter], (async) => { - bootstrap( - WrongComponentTypeCmp, - [bind(ROUTER_PRIMARY_COMPONENT).toValue(WrongComponentTypeCmp), testBindings]) + bootstrap(WrongComponentTypeCmp, testBindings) .catch((e) => { expect(e.originalException) .toContainError( @@ -165,8 +156,7 @@ export function main() { inject( [AsyncTestCompleter], (async) => { - bootstrap(BadAliasCmp, - [bind(ROUTER_PRIMARY_COMPONENT).toValue(BadAliasCmp), testBindings]) + bootstrap(BadAliasCmp, testBindings) .catch((e) => { expect(e.originalException) .toContainError( diff --git a/modules/examples/src/routing/index.ts b/modules/examples/src/routing/index.ts index a7a86a4ef1..11fbecb0dc 100644 --- a/modules/examples/src/routing/index.ts +++ b/modules/examples/src/routing/index.ts @@ -1,13 +1,12 @@ import {InboxApp} from './inbox-app'; import {bind} from 'angular2/angular2'; import {bootstrap} from 'angular2/bootstrap'; -import {routerBindings, HashLocationStrategy, LocationStrategy} from 'angular2/router'; +import {ROUTER_BINDINGS, 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, - [routerBindings(InboxApp), bind(LocationStrategy).toClass(HashLocationStrategy)]); + bootstrap(InboxApp, [ROUTER_BINDINGS, bind(LocationStrategy).toClass(HashLocationStrategy)]); }