X Tutup
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/angular2/src/router/async_route_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export class AsyncRouteHandler implements RouteHandler {
_resolvedComponent: Promise<any> = null;
componentType: Type;

constructor(private _loader: Function) {}
constructor(private _loader: Function, public data?: Object) {}

resolveComponentType(): Promise<any> {
if (isPresent(this._resolvedComponent)) {
Expand Down
3 changes: 2 additions & 1 deletion modules/angular2/src/router/instruction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export class RouteParams {
get(param: string): string { return normalizeBlank(StringMapWrapper.get(this.params, param)); }
}


/**
* `Instruction` is a tree of `ComponentInstructions`, with all the information needed
* to transition each component in the app to a given route, including all auxiliary routes.
Expand Down Expand Up @@ -98,4 +97,6 @@ export class ComponentInstruction {
get specificity() { return this._recognizer.specificity; }

get terminal() { return this._recognizer.terminal; }

routeData(): Object { return this._recognizer.handler.data; }
}
9 changes: 8 additions & 1 deletion modules/angular2/src/router/route_config_decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import {RouteConfig as RouteConfigAnnotation, RouteDefinition} from './route_con
import {makeDecorator} from 'angular2/src/util/decorators';
import {List} from 'angular2/src/facade/collection';

export {Route, Redirect, AuxRoute, AsyncRoute, RouteDefinition} from './route_config_impl';
export {
Route,
Redirect,
AuxRoute,
AsyncRoute,
RouteDefinition,
ROUTE_DATA
} from './route_config_impl';
export var RouteConfig: (configs: List<RouteDefinition>) => ClassDecorator =
makeDecorator(RouteConfigAnnotation);
18 changes: 15 additions & 3 deletions modules/angular2/src/router/route_config_impl.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {CONST, Type} from 'angular2/src/facade/lang';
import {CONST, CONST_EXPR, Type} from 'angular2/src/facade/lang';
import {List} from 'angular2/src/facade/collection';
import {RouteDefinition} from './route_definition';
export {RouteDefinition} from './route_definition';
import {OpaqueToken} from 'angular2/di';

export const ROUTE_DATA: OpaqueToken = CONST_EXPR(new OpaqueToken('routeData'));

/**
* You use the RouteConfig annotation to add routes to a component.
Expand All @@ -19,23 +22,29 @@ export class RouteConfig {

@CONST()
export class Route implements RouteDefinition {
data: any;
path: string;
component: Type;
as: string;
// added next two properties to work around https://github.com/Microsoft/TypeScript/issues/4107
loader: Function;
redirectTo: string;
constructor({path, component, as}: {path: string, component: Type, as?: string}) {
constructor({path, component, as, data}:
{path: string, component: Type, as?: string, data?: any}) {
this.path = path;
this.component = component;
this.as = as;
this.loader = null;
this.redirectTo = null;
this.data = data;
}
}



@CONST()
export class AuxRoute implements RouteDefinition {
data: any = null;
path: string;
component: Type;
as: string;
Expand All @@ -51,13 +60,15 @@ export class AuxRoute implements RouteDefinition {

@CONST()
export class AsyncRoute implements RouteDefinition {
data: any;
path: string;
loader: Function;
as: string;
constructor({path, loader, as}: {path: string, loader: Function, as?: string}) {
constructor({path, loader, as, data}: {path: string, loader: Function, as?: string, data?: any}) {
this.path = path;
this.loader = loader;
this.as = as;
this.data = data;
}
}

Expand All @@ -68,6 +79,7 @@ export class Redirect implements RouteDefinition {
as: string = null;
// added next property to work around https://github.com/Microsoft/TypeScript/issues/4107
loader: Function = null;
data: any = null;
constructor({path, redirectTo}: {path: string, redirectTo: string}) {
this.path = path;
this.redirectTo = redirectTo;
Expand Down
1 change: 1 addition & 0 deletions modules/angular2/src/router/route_definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface RouteDefinition {
loader?: Function;
redirectTo?: string;
as?: string;
data?: any;
}

export interface ComponentDefinition {
Expand Down
1 change: 1 addition & 0 deletions modules/angular2/src/router/route_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ import {Type} from 'angular2/src/facade/lang';
export interface RouteHandler {
componentType: Type;
resolveComponentType(): Promise<any>;
data?: Object;
}
6 changes: 3 additions & 3 deletions modules/angular2/src/router/route_recognizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class RouteRecognizer {
var handler;

if (config instanceof AuxRoute) {
handler = new SyncRouteHandler(config.component);
handler = new SyncRouteHandler(config.component, config.data);
let path = config.path.startsWith('/') ? config.path.substring(1) : config.path;
var recognizer = new PathRecognizer(config.path, handler);
this.auxRoutes.set(path, recognizer);
Expand All @@ -58,9 +58,9 @@ export class RouteRecognizer {
}

if (config instanceof Route) {
handler = new SyncRouteHandler(config.component);
handler = new SyncRouteHandler(config.component, config.data);
} else if (config instanceof AsyncRoute) {
handler = new AsyncRouteHandler(config.loader);
handler = new AsyncRouteHandler(config.loader, config.data);
}
var recognizer = new PathRecognizer(config.path, handler);

Expand Down
6 changes: 4 additions & 2 deletions modules/angular2/src/router/router_outlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {Injector, bind, Dependency, UNDEFINED} from 'angular2/di';

import * as routerMod from './router';
import {Instruction, ComponentInstruction, RouteParams} from './instruction';
import {ROUTE_DATA} from './route_config_impl';
import * as hookMod from './lifecycle_annotations';
import {hasLifecycleHook} from './route_lifecycle_reflector';

Expand Down Expand Up @@ -77,8 +78,9 @@ export class RouterOutlet {
this.childRouter = this._parentRouter.childRouter(componentType);

var bindings = Injector.resolve([
bind(RouteParams)
.toValue(new RouteParams(instruction.params)),
bind(ROUTE_DATA)
.toValue(instruction.routeData()),
bind(RouteParams).toValue(new RouteParams(instruction.params)),
bind(routerMod.Router).toValue(this.childRouter)
]);
return this._loader.loadNextToLocation(componentType, this._elementRef, bindings)
Expand Down
2 changes: 1 addition & 1 deletion modules/angular2/src/router/sync_route_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {Type} from 'angular2/src/facade/lang';
export class SyncRouteHandler implements RouteHandler {
_resolvedComponent: Promise<any> = null;

constructor(public componentType: Type) {
constructor(public componentType: Type, public data?: Object) {
this._resolvedComponent = PromiseWrapper.resolve(componentType);
}

Expand Down
104 changes: 101 additions & 3 deletions modules/angular2/test/router/outlet_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import {
xit
} from 'angular2/test_lib';

import {Injector, bind} from 'angular2/di';
import {Injector, Inject, bind} from 'angular2/di';
import {Component, View} from 'angular2/metadata';
import {CONST, NumberWrapper, isPresent} from 'angular2/src/facade/lang';
import {CONST, NumberWrapper, isPresent, Json} from 'angular2/src/facade/lang';
import {
Promise,
PromiseWrapper,
Expand All @@ -28,7 +28,7 @@ import {

import {RootRouter} from 'angular2/src/router/router';
import {Pipeline} from 'angular2/src/router/pipeline';
import {Router, RouterOutlet, RouterLink, RouteParams} from 'angular2/router';
import {Router, RouterOutlet, RouterLink, RouteParams, ROUTE_DATA} from 'angular2/router';
import {
RouteConfig,
Route,
Expand Down Expand Up @@ -253,6 +253,91 @@ export function main() {
});
}));

it('should inject RouteData into component', inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => rtr.config([
new Route({path: '/route-data', component: RouteDataCmp, data: {'isAdmin': true}})
]))
.then((_) => rtr.navigate('/route-data'))
.then((_) => {
rootTC.detectChanges();
expect(rootTC.nativeElement).toHaveText(Json.stringify({'isAdmin': true}));
async.done();
});
}));

it('should inject RouteData into component with AsyncRoute',
inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => rtr.config([
new AsyncRoute(
{path: '/route-data', loader: AsyncRouteDataCmp, data: {isAdmin: true}})
]))
.then((_) => rtr.navigate('/route-data'))
.then((_) => {
rootTC.detectChanges();
expect(rootTC.nativeElement).toHaveText(Json.stringify({'isAdmin': true}));
async.done();
});
}));

it('should inject nested RouteData into component', inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => rtr.config([
new Route({
path: '/route-data-nested',
component: RouteDataCmp,
data: {'isAdmin': true, 'test': {'moreData': 'testing'}}
})
]))
.then((_) => rtr.navigate('/route-data-nested'))
.then((_) => {
rootTC.detectChanges();
expect(rootTC.nativeElement)
.toHaveText(Json.stringify({'isAdmin': true, 'test': {'moreData': 'testing'}}));
async.done();
});
}));

it('should inject null if the route has no data property',
inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => rtr.config(
[new Route({path: '/route-data-default', component: RouteDataCmp})]))
.then((_) => rtr.navigate('/route-data-default'))
.then((_) => {
rootTC.detectChanges();
expect(rootTC.nativeElement).toHaveText('null');
async.done();
});
}));

it('should allow an array as the route data', inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => rtr.config([
new Route({path: '/route-data-array', component: RouteDataCmp, data: [1, 2, 3]})
]))
.then((_) => rtr.navigate('/route-data-array'))
.then((_) => {
rootTC.detectChanges();
expect(rootTC.nativeElement).toHaveText(Json.stringify([1, 2, 3]));
async.done();
});
}));

it('should allow a string as the route data', inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => rtr.config([
new Route(
{path: '/route-data-string', component: RouteDataCmp, data: 'hello world'})
]))
.then((_) => rtr.navigate('/route-data-string'))
.then((_) => {
rootTC.detectChanges();
expect(rootTC.nativeElement).toHaveText(Json.stringify('hello world'));
async.done();
});
}));

describe('lifecycle hooks', () => {
it('should call the onActivate hook', inject([AsyncTestCompleter], (async) => {
Expand Down Expand Up @@ -633,6 +718,19 @@ class B {
}


function AsyncRouteDataCmp() {
return PromiseWrapper.resolve(RouteDataCmp);
}

@Component({selector: 'data-cmp'})
@View({template: "{{myData}}"})
class RouteDataCmp {
myData: string;
constructor(@Inject(ROUTE_DATA) data: any) {
this.myData = isPresent(data) ? Json.stringify(data) : 'null';
}
}

@Component({selector: 'user-cmp'})
@View({template: "hello {{user}}"})
class UserCmp {
Expand Down
X Tutup