refactor(router): rename "as" to "name" in RouteConfig

BREAKING CHANGE:

This is a rename to make routing concepts easier to understand.

Before:

```
@RouteConfig([
  { path: '/', component: MyCmp, as: 'Home' }
])
```

After:

```
@RouteConfig([
  { path: '/', component: MyCmp, name: 'Home' }
])
```

Closes #4622

Closes #4896
This commit is contained in:
Vamsi V 2015-10-25 15:00:27 +05:30 committed by Brian Ford
parent cc37d0a7fa
commit 7d83959be5
18 changed files with 158 additions and 110 deletions

View File

@ -205,7 +205,7 @@ describe('Navigation lifecycle', function () {
$router.config([
{ path: '/on-reuse/:number/...', component: 'reuseCmp' },
{ path: '/two', component: 'twoCmp', as: 'Two'}
{ path: '/two', component: 'twoCmp', name: 'Two'}
]);
compile('outer { <div ng-outlet></div> }');
@ -247,7 +247,7 @@ describe('Navigation lifecycle', function () {
$router.config([
{ path: '/never-reuse/:number/...', component: 'reuseCmp' },
{ path: '/two', component: 'twoCmp', as: 'Two'}
{ path: '/two', component: 'twoCmp', name: 'Two'}
]);
compile('outer { <div ng-outlet></div> }');

View File

@ -30,7 +30,7 @@ describe('ngLink', function () {
it('should allow linking from the parent to the child', function () {
$router.config([
{ path: '/a', component: 'oneCmp' },
{ path: '/b', component: 'twoCmp', as: 'Two' }
{ path: '/b', component: 'twoCmp', name: 'Two' }
]);
compile('<a ng-link="[\'/Two\']">link</a> | outer { <div ng-outlet></div> }');
@ -43,7 +43,7 @@ describe('ngLink', function () {
it('should allow linking from the child and the parent', function () {
$router.config([
{ path: '/a', component: 'oneCmp' },
{ path: '/b', component: 'twoCmp', as: 'Two' }
{ path: '/b', component: 'twoCmp', name: 'Two' }
]);
compile('outer { <div ng-outlet></div> }');
@ -59,7 +59,7 @@ describe('ngLink', function () {
$router.config([
{ path: '/a', component: 'twoLinkCmp' },
{ path: '/b/:param', component: 'twoCmp', as: 'Two' }
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
]);
compile('<div ng-outlet></div>');
@ -74,7 +74,7 @@ describe('ngLink', function () {
registerComponent('twoLinkCmp', '<div><a ng-link="[\'/Two\', {param: twoLinkCmp.number}]">{{twoLinkCmp.number}}</a></div>', function () {this.number = 'param'});
$router.config([
{ path: '/a', component: 'twoLinkCmp' },
{ path: '/b/:param', component: 'twoCmp', as: 'Two' }
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
]);
compile('<div ng-outlet></div>');
@ -88,7 +88,7 @@ describe('ngLink', function () {
it('should navigate on left-mouse click when a link url matches a route', function () {
$router.config([
{ path: '/', component: 'oneCmp' },
{ path: '/two', component: 'twoCmp', as: 'Two'}
{ path: '/two', component: 'twoCmp', name: 'Two'}
]);
compile('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
@ -107,7 +107,7 @@ describe('ngLink', function () {
it('should not navigate on non-left mouse click when a link url matches a route', inject(function ($router) {
$router.config([
{ path: '/', component: 'oneCmp' },
{ path: '/two', component: 'twoCmp', as: 'Two'}
{ path: '/two', component: 'twoCmp', name: 'Two'}
]);
compile('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
@ -124,7 +124,7 @@ describe('ngLink', function () {
it('should not navigate a link without an href', function () {
$router.config([
{ path: '/', component: 'oneCmp' },
{ path: '/two', component: 'twoCmp', as: 'Two'}
{ path: '/two', component: 'twoCmp', name: 'Two'}
]);
expect(function () {
compile('<a>link</a>');

View File

@ -43,8 +43,8 @@ class HomeCmp {
directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
{path: '/user-settings/:id', component: ControlPanelCmp, as: 'ControlPanelCmp'},
{path: '/', component: HomeCmp, as: 'HomeCmp'}
{path: '/user-settings/:id', component: ControlPanelCmp, name: 'ControlPanelCmp'},
{path: '/', component: HomeCmp, name: 'HomeCmp'}
])
class AppCmp {
}

View File

@ -53,8 +53,8 @@ class NoteIndexCmp {
directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
{path: '/note/:id', component: NoteCmp, as: 'NoteCmp'},
{path: '/', component: NoteIndexCmp, as: 'NoteIndexCmp'}
{path: '/note/:id', component: NoteCmp, name: 'NoteCmp'},
{path: '/', component: NoteIndexCmp, name: 'NoteIndexCmp'}
])
class AppCmp {
}

View File

@ -33,8 +33,8 @@ class MyCmp implements OnActivate {
directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
{path: '/', component: MyCmp, as: 'HomeCmp'},
{path: '/:param', component: MyCmp, as: 'ParamCmp'}
{path: '/', component: MyCmp, name: 'HomeCmp'},
{path: '/:param', component: MyCmp, name: 'ParamCmp'}
])
class AppCmp {
}

View File

@ -46,8 +46,8 @@ class MyCmp implements OnDeactivate {
directives: [ROUTER_DIRECTIVES, NgFor]
})
@RouteConfig([
{path: '/', component: MyCmp, as: 'HomeCmp'},
{path: '/:param', component: MyCmp, as: 'ParamCmp'}
{path: '/', component: MyCmp, name: 'HomeCmp'},
{path: '/:param', component: MyCmp, name: 'ParamCmp'}
])
class AppCmp {
constructor(public logService: LogService) {}

View File

@ -44,8 +44,8 @@ class MyCmp implements CanReuse,
directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
{path: '/', component: MyCmp, as: 'HomeCmp'},
{path: '/:name', component: MyCmp, as: 'HomeCmp'}
{path: '/', component: MyCmp, name: 'HomeCmp'},
{path: '/:name', component: MyCmp, name: 'HomeCmp'}
])
class AppCmp {
}

View File

@ -1,4 +1,4 @@
import {CONST, Type} from 'angular2/src/core/facade/lang';
import {CONST, Type, isPresent} from 'angular2/src/core/facade/lang';
import {RouteDefinition} from './route_definition';
export {RouteDefinition} from './route_definition';
@ -18,7 +18,7 @@ export class RouteConfig {
* It has the following properties:
* - `path` is a string that uses the route matcher DSL.
* - `component` a component type.
* - `as` is an optional `CamelCase` string representing the name of the route.
* - `name` is an optional `CamelCase` string representing the name of the route.
* - `data` is an optional property of any type representing arbitrary route metadata for the given
* route. It is injectable via {@link RouteData}.
*
@ -27,7 +27,7 @@ export class RouteConfig {
* import {RouteConfig} from 'angular2/router';
*
* @RouteConfig([
* {path: '/home', component: HomeCmp, as: 'HomeCmp' }
* {path: '/home', component: HomeCmp, name: 'HomeCmp' }
* ])
* class MyApp {}
* ```
@ -37,15 +37,15 @@ export class Route implements RouteDefinition {
data: {[key: string]: any};
path: string;
component: Type;
as: string;
name: string;
// added next two properties to work around https://github.com/Microsoft/TypeScript/issues/4107
loader: Function;
redirectTo: string;
constructor({path, component, as,
data}: {path: string, component: Type, as?: string, data?: {[key: string]: any}}) {
constructor({path, component, name,
data}: {path: string, component: Type, name?: string, data?: {[key: string]: any}}) {
this.path = path;
this.component = component;
this.as = as;
this.name = name;
this.loader = null;
this.redirectTo = null;
this.data = data;
@ -58,7 +58,7 @@ export class Route implements RouteDefinition {
* It takes an object with the following properties:
* - `path` is a string that uses the route matcher DSL.
* - `component` a component type.
* - `as` is an optional `CamelCase` string representing the name of the route.
* - `name` is an optional `CamelCase` string representing the name of the route.
* - `data` is an optional property of any type representing arbitrary route metadata for the given
* route. It is injectable via {@link RouteData}.
*
@ -77,14 +77,14 @@ export class AuxRoute implements RouteDefinition {
data: {[key: string]: any} = null;
path: string;
component: Type;
as: string;
name: string;
// added next two properties to work around https://github.com/Microsoft/TypeScript/issues/4107
loader: Function = null;
redirectTo: string = null;
constructor({path, component, as}: {path: string, component: Type, as?: string}) {
constructor({path, component, name}: {path: string, component: Type, name?: string}) {
this.path = path;
this.component = component;
this.as = as;
this.name = name;
}
}
@ -95,7 +95,7 @@ export class AuxRoute implements RouteDefinition {
* It has the following properties:
* - `path` is a string that uses the route matcher DSL.
* - `loader` is a function that returns a promise that resolves to a component.
* - `as` is an optional `CamelCase` string representing the name of the route.
* - `name` is an optional `CamelCase` string representing the name of the route.
* - `data` is an optional property of any type representing arbitrary route metadata for the given
* route. It is injectable via {@link RouteData}.
*
@ -104,7 +104,7 @@ export class AuxRoute implements RouteDefinition {
* import {RouteConfig} from 'angular2/router';
*
* @RouteConfig([
* {path: '/home', loader: () => Promise.resolve(MyLoadedCmp), as: 'MyLoadedCmp'}
* {path: '/home', loader: () => Promise.resolve(MyLoadedCmp), name: 'MyLoadedCmp'}
* ])
* class MyApp {}
* ```
@ -114,12 +114,12 @@ export class AsyncRoute implements RouteDefinition {
data: {[key: string]: any};
path: string;
loader: Function;
as: string;
constructor({path, loader, as,
data}: {path: string, loader: Function, as?: string, data?: {[key: string]: any}}) {
name: string;
constructor({path, loader, name, data}:
{path: string, loader: Function, name?: string, data?: {[key: string]: any}}) {
this.path = path;
this.loader = loader;
this.as = as;
this.name = name;
this.data = data;
}
}
@ -147,7 +147,7 @@ export class AsyncRoute implements RouteDefinition {
export class Redirect implements RouteDefinition {
path: string;
redirectTo: string;
as: string = null;
name: string = null;
// added next property to work around https://github.com/Microsoft/TypeScript/issues/4107
loader: Function = null;
data: any = null;

View File

@ -17,8 +17,14 @@ export function normalizeRouteConfig(config: RouteDefinition): RouteDefinition {
throw new BaseException(
`Route config should contain exactly one "component", "loader", or "redirectTo" property.`);
}
if (config.as && config.name) {
throw new BaseException(`Route config should contain exactly one "as" or "name" property.`);
}
if (config.as) {
config.name = config.as;
}
if (config.loader) {
return new AsyncRoute({path: config.path, loader: config.loader, as: config.as});
return new AsyncRoute({path: config.path, loader: config.loader, name: config.name});
}
if (config.component) {
if (typeof config.component == 'object') {
@ -27,11 +33,11 @@ export function normalizeRouteConfig(config: RouteDefinition): RouteDefinition {
return new Route({
path: config.path,
component:<Type>componentDefinitionObject.constructor,
as: config.as
name: config.name
});
} else if (componentDefinitionObject.type == 'loader') {
return new AsyncRoute(
{path: config.path, loader: componentDefinitionObject.loader, as: config.as});
{path: config.path, loader: componentDefinitionObject.loader, name: config.name});
} else {
throw new BaseException(
`Invalid component type "${componentDefinitionObject.type}". Valid types are "constructor" and "loader".`);
@ -40,7 +46,7 @@ export function normalizeRouteConfig(config: RouteDefinition): RouteDefinition {
return new Route(<{
path: string;
component: Type;
as?: string
name?: string;
}>config);
}

View File

@ -2,6 +2,6 @@ library angular2.src.router.route_definition;
abstract class RouteDefinition {
final String path;
final String as;
const RouteDefinition({this.path, this.as});
final String name;
const RouteDefinition({this.path, this.name});
}

View File

@ -6,7 +6,7 @@ import {CONST, Type} from 'angular2/src/core/facade/lang';
* Supported keys:
* - `path` (required)
* - `component`, `loader`, `redirectTo` (requires exactly one of these)
* - `as` (optional)
* - `name` or `as` (optional) (requires exactly one of these)
* - `data` (optional)
*
* See also {@link Route}, {@link AsyncRoute}, {@link AuxRoute}, and {@link Redirect}.
@ -17,6 +17,7 @@ export interface RouteDefinition {
loader?: Function;
redirectTo?: string;
as?: string;
name?: string;
data?: any;
}

View File

@ -38,10 +38,10 @@ export class RouteRecognizer {
config(config: RouteDefinition): boolean {
var handler;
if (isPresent(config.as) && config.as[0].toUpperCase() != config.as[0]) {
var suggestedAlias = config.as[0].toUpperCase() + config.as.substring(1);
if (isPresent(config.name) && config.name[0].toUpperCase() != config.name[0]) {
var suggestedName = config.name[0].toUpperCase() + config.name.substring(1);
throw new BaseException(
`Route '${config.path}' with alias '${config.as}' does not begin with an uppercase letter. Route aliases should be CamelCase like '${suggestedAlias}'.`);
`Route "${config.path}" with name "${config.name}" does not begin with an uppercase letter. Route names should be CamelCase like "${suggestedName}".`);
}
if (config instanceof AuxRoute) {
@ -72,8 +72,8 @@ export class RouteRecognizer {
});
this.matchers.push(recognizer);
if (isPresent(config.as)) {
this.names.set(config.as, recognizer);
if (isPresent(config.name)) {
this.names.set(config.name, recognizer);
}
return recognizer.terminal;
}

View File

@ -77,8 +77,8 @@ export function main() {
inject([AsyncTestCompleter], (async) => {
location.setBaseHref('/my/base');
compile('<a href="hello" [router-link]="[\'./User\']"></a>')
.then((_) =>
router.config([new Route({path: '/user', component: UserCmp, as: 'User'})]))
.then((_) => router.config(
[new Route({path: '/user', component: UserCmp, name: 'User'})]))
.then((_) => router.navigateByUrl('/a/b'))
.then((_) => {
rootTC.detectChanges();
@ -90,8 +90,8 @@ export function main() {
it('should generate link hrefs without params', inject([AsyncTestCompleter], (async) => {
compile('<a href="hello" [router-link]="[\'./User\']"></a>')
.then((_) =>
router.config([new Route({path: '/user', component: UserCmp, as: 'User'})]))
.then((_) => router.config(
[new Route({path: '/user', component: UserCmp, name: 'User'})]))
.then((_) => router.navigateByUrl('/a/b'))
.then((_) => {
rootTC.detectChanges();
@ -104,7 +104,7 @@ export function main() {
it('should generate link hrefs with params', inject([AsyncTestCompleter], (async) => {
compile('<a href="hello" [router-link]="[\'./User\', {name: name}]">{{name}}</a>')
.then((_) => router.config(
[new Route({path: '/user/:name', component: UserCmp, as: 'User'})]))
[new Route({path: '/user/:name', component: UserCmp, name: 'User'})]))
.then((_) => router.navigateByUrl('/a/b'))
.then((_) => {
rootTC.debugElement.componentInstance.name = 'brian';
@ -120,8 +120,9 @@ export function main() {
it('should generate link hrefs from a child to its sibling',
inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => router.config(
[new Route({path: '/page/:number', component: SiblingPageCmp, as: 'Page'})]))
.then(
(_) => router.config(
[new Route({path: '/page/:number', component: SiblingPageCmp, name: 'Page'})]))
.then((_) => router.navigateByUrl('/page/1'))
.then((_) => {
rootTC.detectChanges();
@ -138,7 +139,8 @@ export function main() {
inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => router.config([
new Route({path: '/page/:number', component: NoPrefixSiblingPageCmp, as: 'Page'})
new Route(
{path: '/page/:number', component: NoPrefixSiblingPageCmp, name: 'Page'})
]))
.then((_) => router.navigateByUrl('/page/1'))
.then((_) => {
@ -156,7 +158,7 @@ export function main() {
inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => router.config([
new Route({path: '/book/:title/...', component: NoPrefixBookCmp, as: 'Book'})
new Route({path: '/book/:title/...', component: NoPrefixBookCmp, name: 'Book'})
]))
.then((_) => router.navigateByUrl('/book/1984/page/1'))
.then((_) => {
@ -174,7 +176,7 @@ export function main() {
inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => router.config([
new Route({path: '/book/:title/...', component: AmbiguousBookCmp, as: 'Book'})
new Route({path: '/book/:title/...', component: AmbiguousBookCmp, name: 'Book'})
]))
.then((_) => router.navigateByUrl('/book/1984/page/1'))
.then((_) => {
@ -193,7 +195,7 @@ export function main() {
new AsyncRoute({
path: '/child-with-grandchild/...',
loader: parentCmpLoader,
as: 'ChildWithGrandchild'
name: 'ChildWithGrandchild'
})
]))
.then((_) => router.navigate(['/ChildWithGrandchild']))
@ -212,7 +214,7 @@ export function main() {
inject([AsyncTestCompleter], (async) => {
compile()
.then((_) => router.config(
[new Route({path: '/book/:title/...', component: BookCmp, as: 'Book'})]))
[new Route({path: '/book/:title/...', component: BookCmp, name: 'Book'})]))
.then((_) => router.navigateByUrl('/book/1984/page/1'))
.then((_) => {
rootTC.detectChanges();
@ -236,8 +238,8 @@ export function main() {
describe('router-link-active CSS class', () => {
it('should be added to the associated element', inject([AsyncTestCompleter], (async) => {
router.config([
new Route({path: '/child', component: HelloCmp, as: 'Child'}),
new Route({path: '/better-child', component: Hello2Cmp, as: 'BetterChild'})
new Route({path: '/child', component: HelloCmp, name: 'Child'}),
new Route({path: '/better-child', component: Hello2Cmp, name: 'BetterChild'})
])
.then((_) => compile(`<a [router-link]="['./Child']" class="child-link">Child</a>
<a [router-link]="['./BetterChild']" class="better-child-link">Better Child</a>
@ -267,11 +269,11 @@ export function main() {
it('should be added to links in child routes', inject([AsyncTestCompleter], (async) => {
router.config([
new Route({path: '/child', component: HelloCmp, as: 'Child'}),
new Route({path: '/child', component: HelloCmp, name: 'Child'}),
new Route({
path: '/child-with-grandchild/...',
component: ParentCmp,
as: 'ChildWithGrandchild'
name: 'ChildWithGrandchild'
})
])
.then((_) => compile(`<a [router-link]="['./Child']" class="child-link">Child</a>
@ -319,7 +321,7 @@ export function main() {
it('should navigate to link hrefs without params', inject([AsyncTestCompleter], (async) => {
compile('<a href="hello" [router-link]="[\'./User\']"></a>')
.then((_) => router.config(
[new Route({path: '/user', component: UserCmp, as: 'User'})]))
[new Route({path: '/user', component: UserCmp, name: 'User'})]))
.then((_) => router.navigateByUrl('/a/b'))
.then((_) => {
rootTC.detectChanges();
@ -340,7 +342,7 @@ export function main() {
location.setBaseHref('/base');
compile('<a href="hello" [router-link]="[\'./User\']"></a>')
.then((_) => router.config(
[new Route({path: '/user', component: UserCmp, as: 'User'})]))
[new Route({path: '/user', component: UserCmp, name: 'User'})]))
.then((_) => router.navigateByUrl('/a/b'))
.then((_) => {
rootTC.detectChanges();
@ -427,8 +429,8 @@ function parentCmpLoader() {
directives: ROUTER_DIRECTIVES
})
@RouteConfig([
new Route({path: '/grandchild', component: HelloCmp, as: 'Grandchild'}),
new Route({path: '/better-grandchild', component: Hello2Cmp, as: 'BetterGrandchild'})
new Route({path: '/grandchild', component: HelloCmp, name: 'Grandchild'}),
new Route({path: '/better-grandchild', component: Hello2Cmp, name: 'BetterGrandchild'})
])
class ParentCmp {
constructor(public router: Router) {}
@ -440,7 +442,7 @@ class ParentCmp {
<router-outlet></router-outlet>`,
directives: ROUTER_DIRECTIVES
})
@RouteConfig([new Route({path: '/page/:number', component: SiblingPageCmp, as: 'Page'})])
@RouteConfig([new Route({path: '/page/:number', component: SiblingPageCmp, name: 'Page'})])
class BookCmp {
title: string;
constructor(params: RouteParams) { this.title = params.get('title'); }
@ -452,7 +454,7 @@ class BookCmp {
<router-outlet></router-outlet>`,
directives: ROUTER_DIRECTIVES
})
@RouteConfig([new Route({path: '/page/:number', component: SiblingPageCmp, as: 'Page'})])
@RouteConfig([new Route({path: '/page/:number', component: SiblingPageCmp, name: 'Page'})])
class NoPrefixBookCmp {
title: string;
constructor(params: RouteParams) { this.title = params.get('title'); }
@ -464,7 +466,7 @@ class NoPrefixBookCmp {
<router-outlet></router-outlet>`,
directives: ROUTER_DIRECTIVES
})
@RouteConfig([new Route({path: '/page/:number', component: SiblingPageCmp, as: 'Book'})])
@RouteConfig([new Route({path: '/page/:number', component: SiblingPageCmp, name: 'Book'})])
class AmbiguousBookCmp {
title: string;
constructor(params: RouteParams) { this.title = params.get('title'); }

View File

@ -153,6 +153,19 @@ export function main() {
})}));
it('should throw if a config has an invalid alias name',
inject(
[AsyncTestCompleter],
(async) => {
bootstrap(BadAliasNameCmp, testBindings)
.catch((e) => {
expect(e.originalException)
.toContainError(
`Route "/child" with name "child" does not begin with an uppercase letter. Route names should be CamelCase like "Child".`);
async.done();
return null;
})}));
it('should throw if a config has an invalid alias name with "as"',
inject(
[AsyncTestCompleter],
(async) => {
@ -160,10 +173,22 @@ export function main() {
.catch((e) => {
expect(e.originalException)
.toContainError(
`Route '/child' with alias 'child' does not begin with an uppercase letter. Route aliases should be CamelCase like 'Child'.`);
`Route "/child" with name "child" does not begin with an uppercase letter. Route names should be CamelCase like "Child".`);
async.done();
return null;
})}));
it('should throw if a config has multiple alias properties "as" and "name"',
inject([AsyncTestCompleter],
(async) => {
bootstrap(MultipleAliasCmp, testBindings)
.catch((e) => {
expect(e.originalException)
.toContainError(
`Route config should contain exactly one "as" or "name" property.`);
async.done();
return null;
})}));
});
}
@ -230,12 +255,24 @@ class HierarchyAppCmp {
class WrongConfigCmp {
}
@Component({selector: 'app-cmp'})
@View({template: `root { <router-outlet></router-outlet> }`, directives: ROUTER_DIRECTIVES})
@RouteConfig([{path: '/child', component: HelloCmp, name: 'child'}])
class BadAliasNameCmp {
}
@Component({selector: 'app-cmp'})
@View({template: `root { <router-outlet></router-outlet> }`, directives: ROUTER_DIRECTIVES})
@RouteConfig([{path: '/child', component: HelloCmp, as: 'child'}])
class BadAliasCmp {
}
@Component({selector: 'app-cmp'})
@View({template: `root { <router-outlet></router-outlet> }`, directives: ROUTER_DIRECTIVES})
@RouteConfig([{path: '/child', component: HelloCmp, as: 'Child', name: 'Child'}])
class MultipleAliasCmp {
}
@Component({selector: 'app-cmp'})
@View({template: `root { <router-outlet></router-outlet> }`, directives: ROUTER_DIRECTIVES})
@RouteConfig([

View File

@ -108,20 +108,20 @@ export function main() {
it('should generate URLs with params', () => {
recognizer.config(new Route({path: '/app/user/:name', component: DummyCmpA, as: 'User'}));
recognizer.config(new Route({path: '/app/user/:name', component: DummyCmpA, name: 'User'}));
var instruction = recognizer.generate('User', {'name': 'misko'});
expect(instruction.urlPath).toEqual('app/user/misko');
});
it('should generate URLs with numeric params', () => {
recognizer.config(new Route({path: '/app/page/:number', component: DummyCmpA, as: 'Page'}));
recognizer.config(new Route({path: '/app/page/:number', component: DummyCmpA, name: 'Page'}));
expect(recognizer.generate('Page', {'number': 42}).urlPath).toEqual('app/page/42');
});
it('should throw in the absence of required params URLs', () => {
recognizer.config(new Route({path: 'app/user/:name', component: DummyCmpA, as: 'User'}));
recognizer.config(new Route({path: 'app/user/:name', component: DummyCmpA, name: 'User'}));
expect(() => recognizer.generate('User', {}))
.toThrowError('Route generator for \'name\' was not included in parameters passed.');
});
@ -129,15 +129,15 @@ export function main() {
it('should throw if the route alias is not CamelCase', () => {
expect(() => recognizer.config(
new Route({path: 'app/user/:name', component: DummyCmpA, as: 'user'})))
new Route({path: 'app/user/:name', component: DummyCmpA, name: 'user'})))
.toThrowError(
`Route 'app/user/:name' with alias 'user' does not begin with an uppercase letter. Route aliases should be CamelCase like 'User'.`);
`Route "app/user/:name" with name "user" does not begin with an uppercase letter. Route names should be CamelCase like "User".`);
});
describe('params', () => {
it('should recognize parameters within the URL path', () => {
recognizer.config(new Route({path: 'profile/:name', component: DummyCmpA, as: 'User'}));
recognizer.config(new Route({path: 'profile/:name', component: DummyCmpA, name: 'User'}));
var solution = recognize(recognizer, '/profile/matsko?comments=all');
expect(solution.params).toEqual({'name': 'matsko', 'comments': 'all'});
});
@ -146,7 +146,7 @@ export function main() {
it('should generate and populate the given static-based route with querystring params',
() => {
recognizer.config(
new Route({path: 'forum/featured', component: DummyCmpA, as: 'ForumPage'}));
new Route({path: 'forum/featured', component: DummyCmpA, name: 'ForumPage'}));
var params = {'start': 10, 'end': 100};
@ -157,7 +157,7 @@ export function main() {
it('should prefer positional params over query params', () => {
recognizer.config(new Route({path: 'profile/:name', component: DummyCmpA, as: 'User'}));
recognizer.config(new Route({path: 'profile/:name', component: DummyCmpA, name: 'User'}));
var solution = recognize(recognizer, '/profile/yegor?name=igor');
expect(solution.params).toEqual({'name': 'yegor'});
@ -165,7 +165,7 @@ export function main() {
it('should ignore matrix params for the top-level component', () => {
recognizer.config(new Route({path: '/home/:subject', component: DummyCmpA, as: 'User'}));
recognizer.config(new Route({path: '/home/:subject', component: DummyCmpA, name: 'User'}));
var solution = recognize(recognizer, '/home;sort=asc/zero;one=1?two=2');
expect(solution.params).toEqual({'subject': 'zero', 'two': '2'});
});

View File

@ -43,7 +43,7 @@ export function main() {
it('should generate URLs starting at the given component', () => {
registry.config(RootHostCmp,
new Route({path: '/first/...', component: DummyParentCmp, as: 'FirstCmp'}));
new Route({path: '/first/...', component: DummyParentCmp, name: 'FirstCmp'}));
expect(stringifyInstruction(registry.generate(['FirstCmp', 'SecondCmp'], RootHostCmp)))
.toEqual('first/second');
@ -54,7 +54,7 @@ export function main() {
it('should generate URLs that account for redirects', () => {
registry.config(
RootHostCmp,
new Route({path: '/first/...', component: DummyParentRedirectCmp, as: 'FirstCmp'}));
new Route({path: '/first/...', component: DummyParentRedirectCmp, name: 'FirstCmp'}));
expect(stringifyInstruction(registry.generate(['FirstCmp'], RootHostCmp)))
.toEqual('first/second');
@ -63,7 +63,7 @@ export function main() {
it('should generate URLs in a hierarchy of redirects', () => {
registry.config(
RootHostCmp,
new Route({path: '/first/...', component: DummyMultipleRedirectCmp, as: 'FirstCmp'}));
new Route({path: '/first/...', component: DummyMultipleRedirectCmp, name: 'FirstCmp'}));
expect(stringifyInstruction(registry.generate(['FirstCmp'], RootHostCmp)))
.toEqual('first/second/third');
@ -72,7 +72,7 @@ export function main() {
it('should generate URLs with params', () => {
registry.config(
RootHostCmp,
new Route({path: '/first/:param/...', component: DummyParentParamCmp, as: 'FirstCmp'}));
new Route({path: '/first/:param/...', component: DummyParentParamCmp, name: 'FirstCmp'}));
var url = stringifyInstruction(registry.generate(
['FirstCmp', {param: 'one'}, 'SecondCmp', {param: 'two'}], RootHostCmp));
@ -80,7 +80,7 @@ export function main() {
});
it('should generate params as an empty StringMap when no params are given', () => {
registry.config(RootHostCmp, new Route({path: '/test', component: DummyCmpA, as: 'Test'}));
registry.config(RootHostCmp, new Route({path: '/test', component: DummyCmpA, name: 'Test'}));
var instruction = registry.generate(['Test'], RootHostCmp);
expect(instruction.component.params).toEqual({});
});
@ -89,7 +89,7 @@ export function main() {
inject([AsyncTestCompleter], (async) => {
registry.config(
RootHostCmp,
new AsyncRoute({path: '/first/...', loader: AsyncParentLoader, as: 'FirstCmp'}));
new AsyncRoute({path: '/first/...', loader: AsyncParentLoader, name: 'FirstCmp'}));
expect(() => registry.generate(['FirstCmp', 'SecondCmp'], RootHostCmp))
.toThrowError('Could not find route named "SecondCmp".');
@ -233,7 +233,7 @@ export function main() {
it('should throw when linkParams are not terminal', () => {
registry.config(RootHostCmp,
new Route({path: '/first/...', component: DummyParentCmp, as: 'First'}));
new Route({path: '/first/...', component: DummyParentCmp, name: 'First'}));
expect(() => { registry.generate(['First'], RootHostCmp); })
.toThrowError('Link "["First"]" does not resolve to a terminal or async instruction.');
});
@ -256,7 +256,7 @@ export function main() {
it('should generate URLs with matrix and query params', () => {
registry.config(
RootHostCmp,
new Route({path: '/first/:param/...', component: DummyParentParamCmp, as: 'FirstCmp'}));
new Route({path: '/first/:param/...', component: DummyParentParamCmp, name: 'FirstCmp'}));
var url = stringifyInstruction(registry.generate(
[
@ -294,7 +294,7 @@ class DummyCmpB {}
@RouteConfig([
new Redirect({path: '/', redirectTo: '/third'}),
new Route({path: '/third', component: DummyCmpB, as: 'ThirdCmp'})
new Route({path: '/third', component: DummyCmpB, name: 'ThirdCmp'})
])
class DummyRedirectCmp {
}
@ -302,23 +302,23 @@ class DummyRedirectCmp {
@RouteConfig([
new Redirect({path: '/', redirectTo: '/second'}),
new Route({path: '/second/...', component: DummyRedirectCmp, as: 'SecondCmp'})
new Route({path: '/second/...', component: DummyRedirectCmp, name: 'SecondCmp'})
])
class DummyMultipleRedirectCmp {
}
@RouteConfig([
new Redirect({path: '/', redirectTo: '/second'}),
new Route({path: '/second', component: DummyCmpB, as: 'SecondCmp'})
new Route({path: '/second', component: DummyCmpB, name: 'SecondCmp'})
])
class DummyParentRedirectCmp {
}
@RouteConfig([new Route({path: '/second', component: DummyCmpB, as: 'SecondCmp'})])
@RouteConfig([new Route({path: '/second', component: DummyCmpB, name: 'SecondCmp'})])
class DummyParentCmp {
}
@RouteConfig([new Route({path: '/second/:param', component: DummyCmpB, as: 'SecondCmp'})])
@RouteConfig([new Route({path: '/second/:param', component: DummyCmpB, name: 'SecondCmp'})])
class DummyParentParamCmp {
}

View File

@ -80,8 +80,8 @@ export function main() {
var outlet = makeDummyOutlet();
router.registerPrimaryOutlet(outlet)
.then((_) =>
router.config([new Route({path: '/a', component: DummyComponent, as: 'A'})]))
.then((_) => router.config(
[new Route({path: '/a', component: DummyComponent, name: 'A'})]))
.then((_) => router.navigate(['/A']))
.then((_) => {
expect(outlet.spy('activate')).toHaveBeenCalled();
@ -134,7 +134,8 @@ export function main() {
});
it('should generate URLs from the root component when the path starts with /', () => {
router.config([new Route({path: '/first/...', component: DummyParentComp, as: 'FirstCmp'})]);
router.config(
[new Route({path: '/first/...', component: DummyParentComp, name: 'FirstCmp'})]);
var instruction = router.generate(['/FirstCmp', 'SecondCmp']);
expect(stringifyInstruction(instruction)).toEqual('first/second');
@ -148,7 +149,7 @@ export function main() {
var outlet = makeDummyOutlet();
router.registerPrimaryOutlet(outlet);
router.config([new AsyncRoute({path: '/first', loader: loader, as: 'FirstCmp'})]);
router.config([new AsyncRoute({path: '/first', loader: loader, name: 'FirstCmp'})]);
var instruction = router.generate(['/FirstCmp']);
router.navigateByInstruction(instruction)
@ -164,8 +165,8 @@ export function main() {
router.registerPrimaryOutlet(outlet)
.then((_) => router.config([
new Route({path: '/a', component: DummyComponent, as: 'A'}),
new Route({path: '/b', component: DummyComponent, as: 'B'})
new Route({path: '/a', component: DummyComponent, name: 'A'}),
new Route({path: '/b', component: DummyComponent, name: 'B'})
]))
.then((_) => router.navigateByUrl('/a'))
.then((_) => {
@ -181,7 +182,7 @@ export function main() {
describe('query string params', () => {
it('should use query string params for the root route', () => {
router.config(
[new Route({path: '/hi/how/are/you', component: DummyComponent, as: 'GreetingUrl'})]);
[new Route({path: '/hi/how/are/you', component: DummyComponent, name: 'GreetingUrl'})]);
var instruction = router.generate(['/GreetingUrl', {'name': 'brad'}]);
var path = stringifyInstruction(instruction);
@ -190,8 +191,9 @@ export function main() {
it('should serialize parameters that are not part of the route definition as query string params',
() => {
router.config(
[new Route({path: '/one/two/:three', component: DummyComponent, as: 'NumberUrl'})]);
router.config([
new Route({path: '/one/two/:three', component: DummyComponent, name: 'NumberUrl'})
]);
var instruction = router.generate(['/NumberUrl', {'three': 'three', 'four': 'four'}]);
var path = stringifyInstruction(instruction);
@ -202,7 +204,7 @@ export function main() {
describe('matrix params', () => {
it('should generate matrix params for each non-root component', () => {
router.config(
[new Route({path: '/first/...', component: DummyParentComp, as: 'FirstCmp'})]);
[new Route({path: '/first/...', component: DummyParentComp, name: 'FirstCmp'})]);
var instruction =
router.generate(['/FirstCmp', {'key': 'value'}, 'SecondCmp', {'project': 'angular'}]);
@ -212,7 +214,7 @@ export function main() {
it('should work with named params', () => {
router.config(
[new Route({path: '/first/:token/...', component: DummyParentComp, as: 'FirstCmp'})]);
[new Route({path: '/first/:token/...', component: DummyParentComp, name: 'FirstCmp'})]);
var instruction =
router.generate(['/FirstCmp', {'token': 'min'}, 'SecondCmp', {'author': 'max'}]);
@ -229,7 +231,7 @@ function loader(): Promise<Type> {
class DummyComponent {}
@RouteConfig([new Route({path: '/second', component: DummyComponent, as: 'SecondCmp'})])
@RouteConfig([new Route({path: '/second', component: DummyComponent, name: 'SecondCmp'})])
class DummyParentComp {
}

View File

@ -145,9 +145,9 @@ class DraftsCmp {
@Component({selector: 'inbox-app', viewProviders: [DbService]})
@View({templateUrl: "inbox-app.html", directives: [RouterOutlet, RouterLink]})
@RouteConfig([
new Route({path: '/', component: InboxCmp, as: 'Inbox'}),
new Route({path: '/drafts', component: DraftsCmp, as: 'Drafts'}),
new Route({path: '/detail/:id', component: InboxDetailCmp, as: 'DetailPage'})
new Route({path: '/', component: InboxCmp, name: 'Inbox'}),
new Route({path: '/drafts', component: DraftsCmp, name: 'Drafts'}),
new Route({path: '/detail/:id', component: InboxDetailCmp, name: 'DetailPage'})
])
export class InboxApp {
router: Router;