From 7d83959be56780b1ba9cf7efb6cd96452bec2761 Mon Sep 17 00:00:00 2001 From: Vamsi V Date: Sun, 25 Oct 2015 15:00:27 +0530 Subject: [PATCH] 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 --- .../test/integration/lifecycle_hook_spec.js | 4 +- modules/angular1_router/test/ng_link_spec.js | 14 +++--- .../ts/can_activate/can_activate_example.ts | 4 +- .../can_deactivate/can_deactivate_example.ts | 4 +- .../ts/on_activate/on_activate_example.ts | 4 +- .../ts/on_deactivate/on_deactivate_example.ts | 4 +- .../examples/router/ts/reuse/reuse_example.ts | 4 +- .../angular2/src/router/route_config_impl.ts | 36 +++++++------- .../src/router/route_config_nomalizer.ts | 14 ++++-- .../angular2/src/router/route_definition.dart | 4 +- .../angular2/src/router/route_definition.ts | 3 +- .../angular2/src/router/route_recognizer.ts | 10 ++-- .../router/integration/router_link_spec.ts | 48 ++++++++++--------- .../angular2/test/router/route_config_spec.ts | 39 ++++++++++++++- .../test/router/route_recognizer_spec.ts | 18 +++---- .../test/router/route_registry_spec.ts | 26 +++++----- modules/angular2/test/router/router_spec.ts | 26 +++++----- modules/playground/src/routing/inbox-app.ts | 6 +-- 18 files changed, 158 insertions(+), 110 deletions(-) diff --git a/modules/angular1_router/test/integration/lifecycle_hook_spec.js b/modules/angular1_router/test/integration/lifecycle_hook_spec.js index 61ee0d531e..4ac9f6414e 100644 --- a/modules/angular1_router/test/integration/lifecycle_hook_spec.js +++ b/modules/angular1_router/test/integration/lifecycle_hook_spec.js @@ -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 {
}'); @@ -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 {
}'); diff --git a/modules/angular1_router/test/ng_link_spec.js b/modules/angular1_router/test/ng_link_spec.js index c1633c305f..95ff2efcb3 100644 --- a/modules/angular1_router/test/ng_link_spec.js +++ b/modules/angular1_router/test/ng_link_spec.js @@ -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('link | outer {
}'); @@ -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 {
}'); @@ -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('
'); @@ -74,7 +74,7 @@ describe('ngLink', function () { registerComponent('twoLinkCmp', '
{{twoLinkCmp.number}}
', 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('
'); @@ -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('link |
'); @@ -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('link |
'); @@ -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('link'); diff --git a/modules/angular2/examples/router/ts/can_activate/can_activate_example.ts b/modules/angular2/examples/router/ts/can_activate/can_activate_example.ts index ea6c88b521..e13ba4b006 100644 --- a/modules/angular2/examples/router/ts/can_activate/can_activate_example.ts +++ b/modules/angular2/examples/router/ts/can_activate/can_activate_example.ts @@ -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 { } diff --git a/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_example.ts b/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_example.ts index 0cea45597e..bf42714492 100644 --- a/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_example.ts +++ b/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_example.ts @@ -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 { } diff --git a/modules/angular2/examples/router/ts/on_activate/on_activate_example.ts b/modules/angular2/examples/router/ts/on_activate/on_activate_example.ts index f1d68519a4..557c9e8255 100644 --- a/modules/angular2/examples/router/ts/on_activate/on_activate_example.ts +++ b/modules/angular2/examples/router/ts/on_activate/on_activate_example.ts @@ -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 { } diff --git a/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_example.ts b/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_example.ts index 95fdc177c4..34152ebf5f 100644 --- a/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_example.ts +++ b/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_example.ts @@ -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) {} diff --git a/modules/angular2/examples/router/ts/reuse/reuse_example.ts b/modules/angular2/examples/router/ts/reuse/reuse_example.ts index 00da6ac7f0..8b0bc05452 100644 --- a/modules/angular2/examples/router/ts/reuse/reuse_example.ts +++ b/modules/angular2/examples/router/ts/reuse/reuse_example.ts @@ -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 { } diff --git a/modules/angular2/src/router/route_config_impl.ts b/modules/angular2/src/router/route_config_impl.ts index 2bdd7acee2..cd6be47d8b 100644 --- a/modules/angular2/src/router/route_config_impl.ts +++ b/modules/angular2/src/router/route_config_impl.ts @@ -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; diff --git a/modules/angular2/src/router/route_config_nomalizer.ts b/modules/angular2/src/router/route_config_nomalizer.ts index 15f511f2c2..013262806d 100644 --- a/modules/angular2/src/router/route_config_nomalizer.ts +++ b/modules/angular2/src/router/route_config_nomalizer.ts @@ -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: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); } diff --git a/modules/angular2/src/router/route_definition.dart b/modules/angular2/src/router/route_definition.dart index 401e563f8e..e5d0a22539 100644 --- a/modules/angular2/src/router/route_definition.dart +++ b/modules/angular2/src/router/route_definition.dart @@ -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}); } diff --git a/modules/angular2/src/router/route_definition.ts b/modules/angular2/src/router/route_definition.ts index 4c923d44a1..d21e2c4e56 100644 --- a/modules/angular2/src/router/route_definition.ts +++ b/modules/angular2/src/router/route_definition.ts @@ -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; } diff --git a/modules/angular2/src/router/route_recognizer.ts b/modules/angular2/src/router/route_recognizer.ts index 5ec7046593..42904412cf 100644 --- a/modules/angular2/src/router/route_recognizer.ts +++ b/modules/angular2/src/router/route_recognizer.ts @@ -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; } diff --git a/modules/angular2/test/router/integration/router_link_spec.ts b/modules/angular2/test/router/integration/router_link_spec.ts index a3e222b8a9..22db57c36c 100644 --- a/modules/angular2/test/router/integration/router_link_spec.ts +++ b/modules/angular2/test/router/integration/router_link_spec.ts @@ -77,8 +77,8 @@ export function main() { inject([AsyncTestCompleter], (async) => { location.setBaseHref('/my/base'); compile('') - .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('') - .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('{{name}}') .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(`Child Better Child @@ -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(`Child @@ -319,7 +321,7 @@ export function main() { it('should navigate to link hrefs without params', inject([AsyncTestCompleter], (async) => { compile('') .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('') .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 { `, 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 { `, 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 { `, 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'); } diff --git a/modules/angular2/test/router/route_config_spec.ts b/modules/angular2/test/router/route_config_spec.ts index 19c3c54700..bf64ad075a 100644 --- a/modules/angular2/test/router/route_config_spec.ts +++ b/modules/angular2/test/router/route_config_spec.ts @@ -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 { }`, directives: ROUTER_DIRECTIVES}) +@RouteConfig([{path: '/child', component: HelloCmp, name: 'child'}]) +class BadAliasNameCmp { +} + @Component({selector: 'app-cmp'}) @View({template: `root { }`, directives: ROUTER_DIRECTIVES}) @RouteConfig([{path: '/child', component: HelloCmp, as: 'child'}]) class BadAliasCmp { } +@Component({selector: 'app-cmp'}) +@View({template: `root { }`, directives: ROUTER_DIRECTIVES}) +@RouteConfig([{path: '/child', component: HelloCmp, as: 'Child', name: 'Child'}]) +class MultipleAliasCmp { +} + @Component({selector: 'app-cmp'}) @View({template: `root { }`, directives: ROUTER_DIRECTIVES}) @RouteConfig([ diff --git a/modules/angular2/test/router/route_recognizer_spec.ts b/modules/angular2/test/router/route_recognizer_spec.ts index 90bd44e170..6f4369d9dd 100644 --- a/modules/angular2/test/router/route_recognizer_spec.ts +++ b/modules/angular2/test/router/route_recognizer_spec.ts @@ -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'}); }); diff --git a/modules/angular2/test/router/route_registry_spec.ts b/modules/angular2/test/router/route_registry_spec.ts index 3b83c26f19..8421694607 100644 --- a/modules/angular2/test/router/route_registry_spec.ts +++ b/modules/angular2/test/router/route_registry_spec.ts @@ -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 { } diff --git a/modules/angular2/test/router/router_spec.ts b/modules/angular2/test/router/router_spec.ts index 9c6ccc91fa..bae43bcf97 100644 --- a/modules/angular2/test/router/router_spec.ts +++ b/modules/angular2/test/router/router_spec.ts @@ -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 { class DummyComponent {} -@RouteConfig([new Route({path: '/second', component: DummyComponent, as: 'SecondCmp'})]) +@RouteConfig([new Route({path: '/second', component: DummyComponent, name: 'SecondCmp'})]) class DummyParentComp { } diff --git a/modules/playground/src/routing/inbox-app.ts b/modules/playground/src/routing/inbox-app.ts index cac2063e4e..aa41d8875b 100644 --- a/modules/playground/src/routing/inbox-app.ts +++ b/modules/playground/src/routing/inbox-app.ts @@ -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;