Skip to content

Commit 90191ce

Browse files
committed
refactor(router): use ApplicationRef to provide the first bootstrapped component as ROUTER_PRIMARY_COMPONENT automatically.
This removes the routerBindings function as it is no longer necessary. ROUTER_BINDINGS will automatically pick the first bootstrapped component to satisfy ROUTER_PRIMARY_COMPONENT. BREAKING CHANGE: Before: bootstrap(MyComponent, [routerBindings(myComponent)]); After: bootstrap(MyComponent, [ROUTER_BINDINGS]); Closes angular#4643
1 parent 19c1bd7 commit 90191ce

9 files changed

Lines changed: 57 additions & 89 deletions

File tree

modules/angular2/router.ts

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,22 @@ import {RouterLink} from './src/router/router_link';
2929
import {RouteRegistry} from './src/router/route_registry';
3030
import {Location} from './src/router/location';
3131
import {bind, OpaqueToken, Binding} from './core';
32-
import {CONST_EXPR, Type} from './src/core/facade/lang';
32+
import {CONST_EXPR} from './src/core/facade/lang';
33+
import {ApplicationRef} from './src/core/application_ref';
34+
import {BaseException} from 'angular2/src/core/facade/exceptions';
35+
3336

3437
/**
3538
* Token used to bind the component with the top-level {@link RouteConfig}s for the
3639
* application.
3740
*
38-
* You can use the {@link routerBindings} function in your {@link bootstrap} bindings to
39-
* simplify setting up these bindings.
40-
*
4141
* ## Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
4242
*
4343
* ```
4444
* import {Component, View} from 'angular2/angular2';
4545
* import {
4646
* ROUTER_DIRECTIVES,
4747
* ROUTER_BINDINGS,
48-
* ROUTER_PRIMARY_COMPONENT,
4948
* RouteConfig
5049
* } from 'angular2/router';
5150
*
@@ -58,10 +57,7 @@ import {CONST_EXPR, Type} from './src/core/facade/lang';
5857
* // ...
5958
* }
6059
*
61-
* bootstrap(AppCmp, [
62-
* ROUTER_BINDINGS,
63-
* bind(ROUTER_PRIMARY_COMPONENT).toValue(AppCmp)
64-
* ]);
60+
* bootstrap(AppCmp, [ROUTER_BINDINGS]);
6561
* ```
6662
*/
6763
export const ROUTER_PRIMARY_COMPONENT: OpaqueToken =
@@ -76,7 +72,7 @@ export const ROUTER_PRIMARY_COMPONENT: OpaqueToken =
7672
*
7773
* ```
7874
* import {Component, View} from 'angular2/angular2';
79-
* import {ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router';
75+
* import {ROUTER_DIRECTIVES, ROUTER_BINDINGS, RouteConfig} from 'angular2/router';
8076
*
8177
* @Component({...})
8278
* @View({directives: [ROUTER_DIRECTIVES]})
@@ -87,27 +83,21 @@ export const ROUTER_PRIMARY_COMPONENT: OpaqueToken =
8783
* // ...
8884
* }
8985
*
90-
* bootstrap(AppCmp, [routerBindings(AppCmp)]);
86+
* bootstrap(AppCmp, ROUTER_BINDINGS);
9187
* ```
9288
*/
9389
export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]);
9490

9591
/**
9692
* A list of {@link Binding}s. To use the router, you must add this to your application.
9793
*
98-
* Note that you also need to bind to {@link ROUTER_PRIMARY_COMPONENT}.
99-
*
100-
* You can use the {@link routerBindings} function in your {@link bootstrap} bindings to
101-
* simplify setting up these bindings.
102-
*
10394
* ## Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
10495
*
10596
* ```
10697
* import {Component, View} from 'angular2/angular2';
10798
* import {
10899
* ROUTER_DIRECTIVES,
109100
* ROUTER_BINDINGS,
110-
* ROUTER_PRIMARY_COMPONENT,
111101
* RouteConfig
112102
* } from 'angular2/router';
113103
*
@@ -120,50 +110,30 @@ export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]);
120110
* // ...
121111
* }
122112
*
123-
* bootstrap(AppCmp, [
124-
* ROUTER_BINDINGS,
125-
* bind(ROUTER_PRIMARY_COMPONENT).toValue(AppCmp)
126-
* ]);
113+
* bootstrap(AppCmp, [ROUTER_BINDINGS]);
127114
* ```
128115
*/
129116
export const ROUTER_BINDINGS: any[] = CONST_EXPR([
130117
RouteRegistry,
131118
CONST_EXPR(new Binding(LocationStrategy, {toClass: PathLocationStrategy})),
132119
Location,
133-
CONST_EXPR(
134-
new Binding(Router,
135-
{
136-
toFactory: routerFactory,
137-
deps: CONST_EXPR([RouteRegistry, Location, ROUTER_PRIMARY_COMPONENT])
138-
}))
120+
CONST_EXPR(new Binding(Router,
121+
{
122+
toFactory: routerFactory,
123+
deps: CONST_EXPR([RouteRegistry, Location, ROUTER_PRIMARY_COMPONENT])
124+
})),
125+
CONST_EXPR(new Binding(
126+
ROUTER_PRIMARY_COMPONENT,
127+
{toFactory: routerPrimaryComponentFactory, deps: CONST_EXPR([ApplicationRef])}))
139128
]);
140129

141130
function routerFactory(registry, location, primaryComponent) {
142131
return new RootRouter(registry, location, primaryComponent);
143132
}
144133

145-
/**
146-
* A list of {@link Binding}s. To use the router, you must add these bindings to
147-
* your application.
148-
*
149-
* ## Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
150-
*
151-
* ```
152-
* import {Component, View} from 'angular2/angular2';
153-
* import {ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router';
154-
*
155-
* @Component({...})
156-
* @View({directives: [ROUTER_DIRECTIVES]})
157-
* @RouteConfig([
158-
* {...},
159-
* ])
160-
* class AppCmp {
161-
* // ...
162-
* }
163-
*
164-
* bootstrap(AppCmp, [routerBindings(AppCmp)]);
165-
* ```
166-
*/
167-
export function routerBindings(primaryComponent: Type): Array<any> {
168-
return [ROUTER_BINDINGS, bind(ROUTER_PRIMARY_COMPONENT).toValue(primaryComponent)];
134+
function routerPrimaryComponentFactory(app) {
135+
if (app.componentTypes.length == 0) {
136+
throw new BaseException("Bootstrap at least one component before injecting Router.");
137+
}
138+
return app.componentTypes[0];
169139
}

modules/angular2/src/core/application_ref.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,10 @@ export class PlatformRef_ extends PlatformRef {
230230

231231
private _initApp(zone: NgZone, bindings: Array<Type | Binding | any[]>): ApplicationRef {
232232
var injector: Injector;
233+
var app: ApplicationRef;
233234
zone.run(() => {
234235
bindings.push(bind(NgZone).toValue(zone));
235-
bindings.push(bind(ApplicationRef).toValue(this));
236+
bindings.push(bind(ApplicationRef).toFactory((): ApplicationRef => app, []));
236237

237238
var exceptionHandler;
238239
try {
@@ -247,7 +248,7 @@ export class PlatformRef_ extends PlatformRef {
247248
}
248249
}
249250
});
250-
var app = new ApplicationRef_(this, zone, injector);
251+
app = new ApplicationRef_(this, zone, injector);
251252
this._applications.push(app);
252253
return app;
253254
}
@@ -312,11 +313,17 @@ export abstract class ApplicationRef {
312313
* Dispose of this application and all of its components.
313314
*/
314315
abstract dispose(): void;
316+
317+
/**
318+
* Get a list of component types registered to this application.
319+
*/
320+
get componentTypes(): Type[] { return unimplemented(); };
315321
}
316322

317323
export class ApplicationRef_ extends ApplicationRef {
318324
private _bootstrapListeners: Function[] = [];
319325
private _rootComponents: ComponentRef[] = [];
326+
private _rootComponentTypes: Type[] = [];
320327

321328
constructor(private _platform: PlatformRef_, private _zone: NgZone, private _injector: Injector) {
322329
super();
@@ -334,6 +341,7 @@ export class ApplicationRef_ extends ApplicationRef {
334341
componentBindings.push(bindings);
335342
}
336343
var exceptionHandler = this._injector.get(ExceptionHandler);
344+
this._rootComponentTypes.push(componentType);
337345
try {
338346
var injector: Injector = this._injector.resolveAndCreateChild(componentBindings);
339347
var compRefToken: Promise<ComponentRef> = injector.get(APP_COMPONENT_REF_PROMISE);
@@ -369,4 +377,6 @@ export class ApplicationRef_ extends ApplicationRef {
369377
this._rootComponents.forEach((ref) => ref.dispose());
370378
this._platform._applicationDisposed(this);
371379
}
380+
381+
get componentTypes(): any[] { return this._rootComponentTypes; }
372382
}

modules/angular2/src/router/hash_location_strategy.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {EventListener, History, Location} from 'angular2/src/core/facade/browser
1818
* import {Component, View} from 'angular2/angular2';
1919
* import {
2020
* ROUTER_DIRECTIVES,
21-
* routerBindings,
21+
* ROUTER_BINDINGS,
2222
* RouteConfig,
2323
* Location
2424
* } from 'angular2/router';
@@ -34,9 +34,7 @@ import {EventListener, History, Location} from 'angular2/src/core/facade/browser
3434
* }
3535
* }
3636
*
37-
* bootstrap(AppCmp, [
38-
* routerBindings(AppCmp)
39-
* ]);
37+
* bootstrap(AppCmp, [ROUTER_BINDINGS]);
4038
* ```
4139
*/
4240
@Injectable()

modules/angular2/src/router/instruction.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {Url} from './url_parser';
1616
*
1717
* ```
1818
* import {bootstrap, Component, View} from 'angular2/angular2';
19-
* import {Router, ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router';
19+
* import {Router, ROUTER_DIRECTIVES, ROUTER_BINDINGS, RouteConfig} from 'angular2/router';
2020
*
2121
* @Component({...})
2222
* @View({directives: [ROUTER_DIRECTIVES]})
@@ -34,7 +34,7 @@ import {Url} from './url_parser';
3434
* }
3535
* }
3636
*
37-
* bootstrap(AppCmp, routerBindings(AppCmp));
37+
* bootstrap(AppCmp, ROUTER_BINDINGS);
3838
* ```
3939
*/
4040
export class RouteParams {
@@ -54,7 +54,7 @@ export class RouteParams {
5454
*
5555
* ```
5656
* import {bootstrap, Component, View} from 'angular2/angular2';
57-
* import {Router, ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router';
57+
* import {Router, ROUTER_DIRECTIVES, ROUTER_BINDINGS, RouteConfig} from 'angular2/router';
5858
*
5959
* @Component({...})
6060
* @View({directives: [ROUTER_DIRECTIVES]})
@@ -68,7 +68,7 @@ export class RouteParams {
6868
* }
6969
* }
7070
*
71-
* bootstrap(AppCmp, routerBindings(AppCmp));
71+
* bootstrap(AppCmp, ROUTER_BINDINGS);
7272
* ```
7373
*/
7474
export class Instruction {

modules/angular2/src/router/location.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {OpaqueToken, Injectable, Optional, Inject} from 'angular2/src/core/di';
1717
*
1818
* ```
1919
* import {Component, View} from 'angular2/angular2';
20-
* import {ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router';
20+
* import {ROUTER_DIRECTIVES, ROUTER_BINDINGS, RouteConfig} from 'angular2/router';
2121
*
2222
* @Component({...})
2323
* @View({directives: [ROUTER_DIRECTIVES]})
@@ -29,7 +29,7 @@ import {OpaqueToken, Injectable, Optional, Inject} from 'angular2/src/core/di';
2929
* }
3030
*
3131
* bootstrap(AppCmp, [
32-
* routerBindings(AppCmp),
32+
* ROUTER_BINDINGS,
3333
* PathLocationStrategy,
3434
* bind(APP_BASE_HREF).toValue('/my/app')
3535
* ]);
@@ -59,7 +59,7 @@ export const APP_BASE_HREF: OpaqueToken = CONST_EXPR(new OpaqueToken('appBaseHre
5959
* import {Component, View} from 'angular2/angular2';
6060
* import {
6161
* ROUTER_DIRECTIVES,
62-
* routerBindings,
62+
* ROUTER_BINDINGS,
6363
* RouteConfig,
6464
* Location
6565
* } from 'angular2/router';
@@ -75,7 +75,7 @@ export const APP_BASE_HREF: OpaqueToken = CONST_EXPR(new OpaqueToken('appBaseHre
7575
* }
7676
* }
7777
*
78-
* bootstrap(AppCmp, [routerBindings(AppCmp)]);
78+
* bootstrap(AppCmp, [ROUTER_BINDINGS]);
7979
* ```
8080
*/
8181
@Injectable()

modules/angular2/src/router/path_location_strategy.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {LocationStrategy} from './location_strategy';
1010
* browser's URL.
1111
*
1212
* `PathLocationStrategy` is the default binding for {@link LocationStrategy}
13-
* provided in {@link routerBindings} and {@link ROUTER_BINDINGS}.
13+
* provided in {@link ROUTER_BINDINGS}.
1414
*
1515
* If you're using `PathLocationStrategy`, you must provide a binding for
1616
* {@link APP_BASE_HREF} to a string representing the URL prefix that should
@@ -27,7 +27,7 @@ import {LocationStrategy} from './location_strategy';
2727
* import {
2828
* APP_BASE_HREF
2929
* ROUTER_DIRECTIVES,
30-
* routerBindings,
30+
* ROUTER_BINDINGS,
3131
* RouteConfig,
3232
* Location
3333
* } from 'angular2/router';
@@ -44,7 +44,7 @@ import {LocationStrategy} from './location_strategy';
4444
* }
4545
*
4646
* bootstrap(AppCmp, [
47-
* routerBindings(AppCmp), // includes binding to PathLocationStrategy
47+
* ROUTER_BINDINGS, // includes binding to PathLocationStrategy
4848
* bind(APP_BASE_HREF).toValue('/my/app')
4949
* ]);
5050
* ```

modules/angular2/test/public_api_spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ var NG_API = [
9090
'ApplicationRef:js',
9191
'ApplicationRef.injector:js',
9292
'ApplicationRef.zone:js',
93+
'ApplicationRef.componentTypes:js',
9394
/*
9495
Abstract methods
9596
'ApplicationRef.bootstrap()',

0 commit comments

Comments
 (0)