2016-04-28 20:50:03 -04:00
|
|
|
import {Component, ComponentRef, ViewContainerRef, ViewChild} from '@angular/core';
|
2016-04-12 12:40:37 -04:00
|
|
|
import {
|
|
|
|
AsyncRoute,
|
|
|
|
Route,
|
|
|
|
Redirect,
|
|
|
|
RouteConfig,
|
|
|
|
RouteParams,
|
|
|
|
RouteData,
|
|
|
|
ROUTER_DIRECTIVES
|
2016-05-02 13:36:58 -04:00
|
|
|
} from '@angular/router-deprecated';
|
2016-04-28 20:50:03 -04:00
|
|
|
import {PromiseWrapper} from '../../../src/facade/async';
|
|
|
|
import {isPresent} from '../../../src/facade/lang';
|
|
|
|
import {DynamicComponentLoader} from '@angular/core/src/linker/dynamic_component_loader';
|
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
2015-11-23 21:07:37 -05:00
|
|
|
|
2015-12-15 18:58:04 -05:00
|
|
|
@Component({selector: 'goodbye-cmp', template: `{{farewell}}`})
|
|
|
|
export class GoodbyeCmp {
|
|
|
|
farewell: string;
|
|
|
|
constructor() { this.farewell = 'goodbye'; }
|
|
|
|
}
|
|
|
|
|
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
2015-11-23 21:07:37 -05:00
|
|
|
@Component({selector: 'hello-cmp', template: `{{greeting}}`})
|
|
|
|
export class HelloCmp {
|
|
|
|
greeting: string;
|
|
|
|
constructor() { this.greeting = 'hello'; }
|
|
|
|
}
|
|
|
|
|
|
|
|
export function helloCmpLoader() {
|
|
|
|
return PromiseWrapper.resolve(HelloCmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Component({selector: 'user-cmp', template: `hello {{user}}`})
|
|
|
|
export class UserCmp {
|
|
|
|
user: string;
|
|
|
|
constructor(params: RouteParams) { this.user = params.get('name'); }
|
|
|
|
}
|
|
|
|
|
|
|
|
export function userCmpLoader() {
|
|
|
|
return PromiseWrapper.resolve(UserCmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'parent-cmp',
|
|
|
|
template: `inner { <router-outlet></router-outlet> }`,
|
|
|
|
directives: [ROUTER_DIRECTIVES],
|
|
|
|
})
|
|
|
|
@RouteConfig([new Route({path: '/b', component: HelloCmp, name: 'Child'})])
|
|
|
|
export class ParentCmp {
|
|
|
|
}
|
|
|
|
|
|
|
|
export function parentCmpLoader() {
|
|
|
|
return PromiseWrapper.resolve(ParentCmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'parent-cmp',
|
|
|
|
template: `inner { <router-outlet></router-outlet> }`,
|
|
|
|
directives: [ROUTER_DIRECTIVES],
|
|
|
|
})
|
|
|
|
@RouteConfig([new AsyncRoute({path: '/b', loader: helloCmpLoader, name: 'Child'})])
|
|
|
|
export class AsyncParentCmp {
|
|
|
|
}
|
|
|
|
|
|
|
|
export function asyncParentCmpLoader() {
|
|
|
|
return PromiseWrapper.resolve(AsyncParentCmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'parent-cmp',
|
|
|
|
template: `inner { <router-outlet></router-outlet> }`,
|
|
|
|
directives: [ROUTER_DIRECTIVES],
|
|
|
|
})
|
|
|
|
@RouteConfig(
|
|
|
|
[new AsyncRoute({path: '/b', loader: helloCmpLoader, name: 'Child', useAsDefault: true})])
|
|
|
|
export class AsyncDefaultParentCmp {
|
|
|
|
}
|
|
|
|
|
|
|
|
export function asyncDefaultParentCmpLoader() {
|
|
|
|
return PromiseWrapper.resolve(AsyncDefaultParentCmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'parent-cmp',
|
|
|
|
template: `inner { <router-outlet></router-outlet> }`,
|
|
|
|
directives: [ROUTER_DIRECTIVES],
|
|
|
|
})
|
|
|
|
@RouteConfig([new Route({path: '/b', component: HelloCmp, name: 'Child', useAsDefault: true})])
|
|
|
|
export class ParentWithDefaultCmp {
|
|
|
|
}
|
|
|
|
|
|
|
|
export function parentWithDefaultCmpLoader() {
|
|
|
|
return PromiseWrapper.resolve(ParentWithDefaultCmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'team-cmp',
|
|
|
|
template: `team {{id}} | user { <router-outlet></router-outlet> }`,
|
|
|
|
directives: [ROUTER_DIRECTIVES],
|
|
|
|
})
|
|
|
|
@RouteConfig([new Route({path: '/user/:name', component: UserCmp, name: 'User'})])
|
|
|
|
export class TeamCmp {
|
|
|
|
id: string;
|
|
|
|
constructor(params: RouteParams) { this.id = params.get('id'); }
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'team-cmp',
|
|
|
|
template: `team {{id}} | user { <router-outlet></router-outlet> }`,
|
|
|
|
directives: [ROUTER_DIRECTIVES],
|
|
|
|
})
|
|
|
|
@RouteConfig([new AsyncRoute({path: '/user/:name', loader: userCmpLoader, name: 'User'})])
|
|
|
|
export class AsyncTeamCmp {
|
|
|
|
id: string;
|
|
|
|
constructor(params: RouteParams) { this.id = params.get('id'); }
|
|
|
|
}
|
|
|
|
|
|
|
|
export function asyncTeamLoader() {
|
|
|
|
return PromiseWrapper.resolve(AsyncTeamCmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Component({selector: 'data-cmp', template: `{{myData}}`})
|
|
|
|
export class RouteDataCmp {
|
|
|
|
myData: boolean;
|
|
|
|
constructor(data: RouteData) { this.myData = data.get('isAdmin'); }
|
|
|
|
}
|
|
|
|
|
|
|
|
export function asyncRouteDataCmp() {
|
|
|
|
return PromiseWrapper.resolve(RouteDataCmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({selector: 'redirect-to-parent-cmp', template: 'redirect-to-parent'})
|
|
|
|
@RouteConfig([new Redirect({path: '/child-redirect', redirectTo: ['../HelloSib']})])
|
|
|
|
export class RedirectToParentCmp {
|
|
|
|
}
|
2016-02-26 13:37:43 -05:00
|
|
|
|
|
|
|
|
|
|
|
@Component({selector: 'dynamic-loader-cmp', template: `{ <div #viewport></div> }`})
|
|
|
|
@RouteConfig([new Route({path: '/', component: HelloCmp})])
|
|
|
|
export class DynamicLoaderCmp {
|
2016-04-30 13:52:04 -04:00
|
|
|
private _componentRef: ComponentRef<any> = null;
|
2016-04-14 15:35:24 -04:00
|
|
|
|
|
|
|
@ViewChild('viewport', {read: ViewContainerRef}) viewport: ViewContainerRef;
|
2016-04-18 16:24:42 -04:00
|
|
|
|
|
|
|
constructor(private _dynamicComponentLoader: DynamicComponentLoader) {}
|
2016-02-26 13:37:43 -05:00
|
|
|
|
|
|
|
onSomeAction(): Promise<any> {
|
|
|
|
if (isPresent(this._componentRef)) {
|
2016-04-13 20:05:17 -04:00
|
|
|
this._componentRef.destroy();
|
2016-02-26 13:37:43 -05:00
|
|
|
this._componentRef = null;
|
|
|
|
}
|
2016-04-14 17:52:35 -04:00
|
|
|
return this._dynamicComponentLoader.loadNextToLocation(DynamicallyLoadedComponent,
|
|
|
|
this.viewport)
|
2016-02-26 13:37:43 -05:00
|
|
|
.then((cmp) => { this._componentRef = cmp; });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'loaded-cmp',
|
|
|
|
template: '<router-outlet></router-outlet>',
|
|
|
|
directives: [ROUTER_DIRECTIVES]
|
|
|
|
})
|
|
|
|
class DynamicallyLoadedComponent {
|
|
|
|
}
|