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.
This commit is contained in:
@ -4,7 +4,6 @@
|
|||||||
* Maps application URLs into application states, to support deep-linking and navigation.
|
* Maps application URLs into application states, to support deep-linking and navigation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
export {Router, RootRouter} from './src/router/router';
|
export {Router, RootRouter} from './src/router/router';
|
||||||
export {RouterOutlet} from './src/router/router_outlet';
|
export {RouterOutlet} from './src/router/router_outlet';
|
||||||
export {RouterLink} from './src/router/router_link';
|
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 {RouterLink} from './src/router/router_link';
|
||||||
import {RouteRegistry} from './src/router/route_registry';
|
import {RouteRegistry} from './src/router/route_registry';
|
||||||
import {Location} from './src/router/location';
|
import {Location} from './src/router/location';
|
||||||
import {APP_COMPONENT} from './src/core/application_tokens';
|
import {bind, OpaqueToken, Binding} from './core';
|
||||||
import {Binding} from './core';
|
import {CONST_EXPR, Type} from './src/core/facade/lang';
|
||||||
import {CONST_EXPR} 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]);
|
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([
|
export const ROUTER_BINDINGS: any[] = CONST_EXPR([
|
||||||
RouteRegistry,
|
RouteRegistry,
|
||||||
CONST_EXPR(new Binding(LocationStrategy, {toClass: PathLocationStrategy})),
|
CONST_EXPR(new Binding(LocationStrategy, {toClass: PathLocationStrategy})),
|
||||||
Location,
|
Location,
|
||||||
CONST_EXPR(new Binding(
|
CONST_EXPR(
|
||||||
Router,
|
new Binding(Router,
|
||||||
{toFactory: routerFactory, deps: CONST_EXPR([RouteRegistry, Location, APP_COMPONENT])}))
|
{
|
||||||
|
toFactory: routerFactory,
|
||||||
|
deps: CONST_EXPR([RouteRegistry, Location, ROUTER_PRIMARY_COMPONENT])
|
||||||
|
}))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function routerFactory(registry, location, appRoot) {
|
function routerFactory(registry, location, primaryComponent) {
|
||||||
return new RootRouter(registry, location, appRoot);
|
return new RootRouter(registry, location, primaryComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function routerBindings(primaryComponent: Type): Array<any> {
|
||||||
|
return [ROUTER_BINDINGS, bind(ROUTER_PRIMARY_COMPONENT).toValue(primaryComponent)];
|
||||||
}
|
}
|
||||||
|
@ -457,13 +457,12 @@ export class Router {
|
|||||||
export class RootRouter extends Router {
|
export class RootRouter extends Router {
|
||||||
_location: Location;
|
_location: Location;
|
||||||
|
|
||||||
constructor(registry: RouteRegistry, location: Location, hostComponent: Type) {
|
constructor(registry: RouteRegistry, location: Location, primaryComponent: Type) {
|
||||||
super(registry, null, hostComponent);
|
super(registry, null, primaryComponent);
|
||||||
this._location = location;
|
this._location = location;
|
||||||
this._location.subscribe((change) =>
|
this._location.subscribe((change) =>
|
||||||
this.navigateByUrl(change['url'], isPresent(change['pop'])));
|
this.navigateByUrl(change['url'], isPresent(change['pop'])));
|
||||||
|
this.registry.configFromComponent(primaryComponent);
|
||||||
this.registry.configFromComponent(hostComponent);
|
|
||||||
this.navigateByUrl(location.path());
|
this.navigateByUrl(location.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import {PromiseWrapper} from 'angular2/src/core/facade/async';
|
|||||||
import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions';
|
import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions';
|
||||||
import {
|
import {
|
||||||
ROUTER_BINDINGS,
|
ROUTER_BINDINGS,
|
||||||
|
ROUTER_PRIMARY_COMPONENT,
|
||||||
RouteParams,
|
RouteParams,
|
||||||
Router,
|
Router,
|
||||||
APP_BASE_HREF,
|
APP_BASE_HREF,
|
||||||
@ -33,7 +34,6 @@ import {
|
|||||||
|
|
||||||
import {LocationStrategy} from 'angular2/src/router/location_strategy';
|
import {LocationStrategy} from 'angular2/src/router/location_strategy';
|
||||||
import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy';
|
import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy';
|
||||||
import {APP_COMPONENT} from 'angular2/src/core/application_tokens';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('router injectables', () => {
|
describe('router injectables', () => {
|
||||||
@ -51,6 +51,7 @@ export function main() {
|
|||||||
bootstrap(AppCmp,
|
bootstrap(AppCmp,
|
||||||
[
|
[
|
||||||
ROUTER_BINDINGS,
|
ROUTER_BINDINGS,
|
||||||
|
bind(ROUTER_PRIMARY_COMPONENT).toValue(AppCmp),
|
||||||
bind(LocationStrategy).toClass(MockLocationStrategy),
|
bind(LocationStrategy).toClass(MockLocationStrategy),
|
||||||
bind(DOCUMENT).toValue(fakeDoc)
|
bind(DOCUMENT).toValue(fakeDoc)
|
||||||
])
|
])
|
||||||
@ -66,7 +67,7 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('broken app', () => {
|
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',
|
it('should rethrow exceptions from component constructors',
|
||||||
inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => {
|
inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => {
|
||||||
@ -82,7 +83,8 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('back button app', () => {
|
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',
|
it('should change the url without pushing a new history state for back navigations',
|
||||||
inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => {
|
inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => {
|
||||||
@ -133,7 +135,8 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('hierarchical app', () => {
|
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',
|
it('should bootstrap an app with a hierarchy',
|
||||||
inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => {
|
inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => {
|
||||||
@ -177,7 +180,8 @@ export function main() {
|
|||||||
// TODO: add a test in which the child component has bindings
|
// TODO: add a test in which the child component has bindings
|
||||||
|
|
||||||
describe('querystring params app', () => {
|
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',
|
it('should recognize and return querystring params with the injected RouteParams',
|
||||||
inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => {
|
inject([AsyncTestCompleter, TestComponentBuilder], (async, tcb: TestComponentBuilder) => {
|
||||||
|
@ -20,6 +20,7 @@ import {Type} from 'angular2/src/core/facade/lang';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ROUTER_BINDINGS,
|
ROUTER_BINDINGS,
|
||||||
|
ROUTER_PRIMARY_COMPONENT,
|
||||||
Router,
|
Router,
|
||||||
RouteConfig,
|
RouteConfig,
|
||||||
APP_BASE_HREF,
|
APP_BASE_HREF,
|
||||||
@ -56,7 +57,8 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should bootstrap an app with a hierarchy', inject([AsyncTestCompleter], (async) => {
|
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) => {
|
.then((applicationRef) => {
|
||||||
var router = applicationRef.hostComponent.router;
|
var router = applicationRef.hostComponent.router;
|
||||||
router.subscribe((_) => {
|
router.subscribe((_) => {
|
||||||
@ -70,7 +72,8 @@ export function main() {
|
|||||||
|
|
||||||
|
|
||||||
it('should work in an app with redirects', inject([AsyncTestCompleter], (async) => {
|
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) => {
|
.then((applicationRef) => {
|
||||||
var router = applicationRef.hostComponent.router;
|
var router = applicationRef.hostComponent.router;
|
||||||
router.subscribe((_) => {
|
router.subscribe((_) => {
|
||||||
@ -84,7 +87,7 @@ export function main() {
|
|||||||
|
|
||||||
|
|
||||||
it('should work in an app with async components', inject([AsyncTestCompleter], (async) => {
|
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) => {
|
.then((applicationRef) => {
|
||||||
var router = applicationRef.hostComponent.router;
|
var router = applicationRef.hostComponent.router;
|
||||||
router.subscribe((_) => {
|
router.subscribe((_) => {
|
||||||
@ -99,7 +102,9 @@ export function main() {
|
|||||||
|
|
||||||
it('should work in an app with a constructor component',
|
it('should work in an app with a constructor component',
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
bootstrap(ExplicitConstructorAppCmp, testBindings)
|
bootstrap(
|
||||||
|
ExplicitConstructorAppCmp,
|
||||||
|
[bind(ROUTER_PRIMARY_COMPONENT).toValue(ExplicitConstructorAppCmp), testBindings])
|
||||||
.then((applicationRef) => {
|
.then((applicationRef) => {
|
||||||
var router = applicationRef.hostComponent.router;
|
var router = applicationRef.hostComponent.router;
|
||||||
router.subscribe((_) => {
|
router.subscribe((_) => {
|
||||||
@ -115,7 +120,8 @@ export function main() {
|
|||||||
inject(
|
inject(
|
||||||
[AsyncTestCompleter],
|
[AsyncTestCompleter],
|
||||||
(async) => {
|
(async) => {
|
||||||
bootstrap(WrongConfigCmp, testBindings)
|
bootstrap(WrongConfigCmp,
|
||||||
|
[bind(ROUTER_PRIMARY_COMPONENT).toValue(WrongConfigCmp), testBindings])
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
expect(e.originalException)
|
expect(e.originalException)
|
||||||
.toContainError(
|
.toContainError(
|
||||||
@ -128,7 +134,9 @@ export function main() {
|
|||||||
inject(
|
inject(
|
||||||
[AsyncTestCompleter],
|
[AsyncTestCompleter],
|
||||||
(async) => {
|
(async) => {
|
||||||
bootstrap(WrongComponentTypeCmp, testBindings)
|
bootstrap(
|
||||||
|
WrongComponentTypeCmp,
|
||||||
|
[bind(ROUTER_PRIMARY_COMPONENT).toValue(WrongComponentTypeCmp), testBindings])
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
expect(e.originalException)
|
expect(e.originalException)
|
||||||
.toContainError(
|
.toContainError(
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import {InboxApp} from './inbox-app';
|
import {InboxApp} from './inbox-app';
|
||||||
import {bind} from 'angular2/angular2';
|
import {bind} from 'angular2/angular2';
|
||||||
import {bootstrap} from 'angular2/bootstrap';
|
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 {reflector} from 'angular2/src/core/reflection/reflection';
|
||||||
import {ReflectionCapabilities} from 'angular2/src/core/reflection/reflection_capabilities';
|
import {ReflectionCapabilities} from 'angular2/src/core/reflection/reflection_capabilities';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||||
bootstrap(InboxApp, [ROUTER_BINDINGS, bind(LocationStrategy).toClass(HashLocationStrategy)]);
|
bootstrap(InboxApp,
|
||||||
|
[routerBindings(InboxApp), bind(LocationStrategy).toClass(HashLocationStrategy)]);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user