refactor(router): improve recognition and generation pipeline

This is a big change. @matsko also deserves much of the credit for the implementation.

Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.

BREAKING CHANGE:

Redirects now use the Link DSL syntax. Before:

```
@RouteConfig([
	{ path: '/foo', redirectTo: '/bar' },
	{ path: '/bar', component: BarCmp }
])
```

After:

```
@RouteConfig([
	{ path: '/foo', redirectTo: ['Bar'] },
	{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```

BREAKING CHANGE:

This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.

Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:

@RouteConfig([
	{ path: '/tab', redirectTo: '/tab/users' }
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }

Now the recommended way to handle this is case is to use `useAsDefault` like so:

```
@RouteConfig([
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }

@RouteConfig([
	{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
	{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```

In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.

Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200

Closes #5475
This commit is contained in:
Brian Ford
2015-11-23 18:07:37 -08:00
parent a3253210b7
commit 6ddfff5cd5
43 changed files with 3113 additions and 1197 deletions

View File

@ -9,7 +9,7 @@ import {
expect,
iit,
inject,
beforeEachBindings,
beforeEachProviders,
it,
xit,
TestComponentBuilder,
@ -21,7 +21,7 @@ import {NumberWrapper} from 'angular2/src/facade/lang';
import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper} from 'angular2/src/facade/collection';
import {provide, Component, DirectiveResolver} from 'angular2/core';
import {provide, Component, View, DirectiveResolver} from 'angular2/core';
import {SpyLocation} from 'angular2/src/mock/location_mock';
import {
@ -35,7 +35,8 @@ import {
Route,
RouteParams,
RouteConfig,
ROUTER_DIRECTIVES
ROUTER_DIRECTIVES,
ROUTER_PRIMARY_COMPONENT
} from 'angular2/router';
import {RootRouter} from 'angular2/src/router/router';
@ -47,16 +48,12 @@ export function main() {
var fixture: ComponentFixture;
var router, location;
beforeEachBindings(() => [
beforeEachProviders(() => [
RouteRegistry,
DirectiveResolver,
provide(Location, {useClass: SpyLocation}),
provide(Router,
{
useFactory:
(registry, location) => { return new RootRouter(registry, location, MyComp); },
deps: [RouteRegistry, Location]
})
provide(ROUTER_PRIMARY_COMPONENT, {useValue: MyComp}),
provide(Router, {useClass: RootRouter})
]);
beforeEach(inject([TestComponentBuilder, Router, Location], (tcBuilder, rtr, loc) => {
@ -240,8 +237,8 @@ export function main() {
.then((_) => router.config([new Route({path: '/...', component: AuxLinkCmp})]))
.then((_) => router.navigateByUrl('/'))
.then((_) => {
rootTC.detectChanges();
expect(DOM.getAttribute(rootTC.debugElement.componentViewChildren[1]
fixture.detectChanges();
expect(DOM.getAttribute(fixture.debugElement.componentViewChildren[1]
.componentViewChildren[0]
.nativeElement,
'href'))
@ -386,10 +383,7 @@ class MyComp {
name;
}
@Component({
selector: 'user-cmp',
template: "hello {{user}}"
})
@Component({selector: 'user-cmp', template: "hello {{user}}"})
class UserCmp {
user: string;
constructor(params: RouteParams) { this.user = params.get('name'); }
@ -425,17 +419,11 @@ class NoPrefixSiblingPageCmp {
}
}
@Component({
selector: 'hello-cmp',
template: 'hello'
})
@Component({selector: 'hello-cmp', template: 'hello'})
class HelloCmp {
}
@Component({
selector: 'hello2-cmp',
template: 'hello2'
})
@Component({selector: 'hello2-cmp', template: 'hello2'})
class Hello2Cmp {
}
@ -455,7 +443,6 @@ function parentCmpLoader() {
new Route({path: '/better-grandchild', component: Hello2Cmp, name: 'BetterGrandchild'})
])
class ParentCmp {
constructor(public router: Router) {}
}
@Component({