From 0a1cbb1e57f74f8ff8bcb945b539b5dd51c512c3 Mon Sep 17 00:00:00 2001 From: Brian Ford Date: Mon, 21 Sep 2015 14:43:24 -0700 Subject: [PATCH 1/4] docs(router): improve docs for RouteDefinition classes --- .../angular2/src/router/route_config_impl.ts | 91 +++++++++++++++++-- .../angular2/src/router/route_definition.ts | 11 +++ 2 files changed, 93 insertions(+), 9 deletions(-) diff --git a/modules/angular2/src/router/route_config_impl.ts b/modules/angular2/src/router/route_config_impl.ts index 93ae1bb84417..93227adb4bb8 100644 --- a/modules/angular2/src/router/route_config_impl.ts +++ b/modules/angular2/src/router/route_config_impl.ts @@ -3,20 +3,35 @@ import {RouteDefinition} from './route_definition'; export {RouteDefinition} from './route_definition'; /** - * You use the RouteConfig annotation to add routes to a component. + * The `RouteConfig` decorator defines routes for a given component. * - * Supported keys: - * - `path` (required) - * - `component`, `loader`, `redirectTo` (requires exactly one of these) - * - `as` (optional) - * - `data` (optional) + * It takes an array of {@link RouteDefinition}s. */ @CONST() export class RouteConfig { constructor(public configs: RouteDefinition[]) {} } - +/** + * `Route` is a type of {@link RouteDefinition} used to route a path to a component. + * + * 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. + * - `data` is an optional property of any type representing arbitrary route metadata for the given + * route. It is injectable via the {@link ROUTE_DATA} token. + * + * ## Example + * ``` + * import {RouteConfig} from 'angular2/router'; + * + * @RouteConfig([ + * {path: '/home', component: HomeCmp, as: 'HomeCmp' } + * ]) + * class MyApp {} + * ``` + */ @CONST() export class Route implements RouteDefinition { data: any; @@ -37,8 +52,26 @@ export class Route implements RouteDefinition { } } - - +/** + * `AuxRoute` is a type of {@link RouteDefinition} used to define an auxiliary route. + * + * 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. + * - `data` is an optional property of any type representing arbitrary route metadata for the given + * route. It is injectable via the {@link ROUTE_DATA} token. + * + * ## Example + * ``` + * import {RouteConfig, AuxRoute} from 'angular2/router'; + * + * @RouteConfig([ + * new AuxRoute({path: '/home', component: HomeCmp}) + * ]) + * class MyApp {} + * ``` + */ @CONST() export class AuxRoute implements RouteDefinition { data: any = null; @@ -55,6 +88,27 @@ export class AuxRoute implements RouteDefinition { } } +/** + * `AsyncRoute` is a type of {@link RouteDefinition} used to route a path to an asynchronously + * loaded component. + * + * 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. + * - `data` is an optional property of any type representing arbitrary route metadata for the given + * route. It is injectable via the {@link ROUTE_DATA} token. + * + * ## Example + * ``` + * import {RouteConfig} from 'angular2/router'; + * + * @RouteConfig([ + * {path: '/home', loader: () => Promise.resolve(MyLoadedCmp), as: 'MyLoadedCmp'} + * ]) + * class MyApp {} + * ``` + */ @CONST() export class AsyncRoute implements RouteDefinition { data: any; @@ -69,6 +123,25 @@ export class AsyncRoute implements RouteDefinition { } } +/** + * `Redirect` is a type of {@link RouteDefinition} used to route a path to an asynchronously loaded + * component. + * + * It has the following properties: + * - `path` is a string that uses the route matcher DSL. + * - `redirectTo` is a string representing the new URL to be matched against. + * + * ## Example + * ``` + * import {RouteConfig} from 'angular2/router'; + * + * @RouteConfig([ + * {path: '/', redirectTo: '/home'}, + * {path: '/home', component: HomeCmp} + * ]) + * class MyApp {} + * ``` + */ @CONST() export class Redirect implements RouteDefinition { path: string; diff --git a/modules/angular2/src/router/route_definition.ts b/modules/angular2/src/router/route_definition.ts index 64eb705c4518..4c923d44a181 100644 --- a/modules/angular2/src/router/route_definition.ts +++ b/modules/angular2/src/router/route_definition.ts @@ -1,5 +1,16 @@ import {CONST, Type} from 'angular2/src/core/facade/lang'; +/** + * `RouteDefinition` defines a route within a {@link RouteConfig} decorator. + * + * Supported keys: + * - `path` (required) + * - `component`, `loader`, `redirectTo` (requires exactly one of these) + * - `as` (optional) + * - `data` (optional) + * + * See also {@link Route}, {@link AsyncRoute}, {@link AuxRoute}, and {@link Redirect}. + */ export interface RouteDefinition { path: string; component?: Type | ComponentDefinition; From b0910bae3422b6bdf7f366bbdb20de8cf94d9b01 Mon Sep 17 00:00:00 2001 From: Brian Ford Date: Mon, 21 Sep 2015 16:25:37 -0700 Subject: [PATCH 2/4] docs(router): improve docs for lifecycle hooks Closes #4300 --- modules/angular2/src/router/interfaces.ts | 115 +++++++++++++----- .../src/router/lifecycle_annotations.ts | 24 +++- 2 files changed, 101 insertions(+), 38 deletions(-) diff --git a/modules/angular2/src/router/interfaces.ts b/modules/angular2/src/router/interfaces.ts index acb91c256f3a..3d9cdc5fefec 100644 --- a/modules/angular2/src/router/interfaces.ts +++ b/modules/angular2/src/router/interfaces.ts @@ -8,76 +8,102 @@ var __ignore_me = global; /** - * Defines route lifecycle method [onActivate], which is called by the router at the end of a + * Defines route lifecycle method `onActivate`, which is called by the router at the end of a * successful route navigation. * - * For a single component's navigation, only one of either [onActivate] or [onReuse] will be called, - * depending on the result of [canReuse]. + * For a single component's navigation, only one of either {@link OnActivate} or {@link OnReuse} + * will be called depending on the result of {@link CanReuse}. + * + * The `onActivate` hook is called with two {@link ComponentInstruction}s as parameters, the first + * representing the current route being navigated to, and the second parameter representing the + * previous route or `null`. * * If `onActivate` returns a promise, the route change will wait until the promise settles to * instantiate and activate child components. * * ## Example * ``` - * @Directive({ + * import {Component, View} from 'angular2/angular2'; + * import {OnActivate, ComponentInstruction} from 'angular2/router'; + * + * @Component({ * selector: 'my-cmp' * }) + * @View({ + * template: '
hello!
' + * }) * class MyCmp implements OnActivate { - * onActivate(next, prev) { + * onActivate(next: ComponentInstruction, prev: ComponentInstruction) { * this.log = 'Finished navigating from ' + prev.urlPath + ' to ' + next.urlPath; * } * } - * ``` + * ``` */ export interface OnActivate { onActivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any; } /** - * Defines route lifecycle method [onReuse], which is called by the router at the end of a - * successful route navigation when [canReuse] is implemented and returns or resolves to true. + * Defines route lifecycle method `onReuse`, which is called by the router at the end of a + * successful route navigation when {@link CanReuse} is implemented and returns or resolves to true. + * + * For a single component's navigation, only one of either {@link OnActivate} or {@link OnReuse} + * will be called, depending on the result of {@link CanReuse}. * - * For a single component's navigation, only one of either [onActivate] or [onReuse] will be called, - * depending on the result of [canReuse]. + * The `onReuse` hook is called with two {@link ComponentInstruction}s as parameters, the first + * representing the current route being navigated to, and the second parameter representing the + * previous route or `null`. * * ## Example * ``` - * @Directive({ + * import {Component, View} from 'angular2/angular2'; + * import {CanReuse, OnReuse, ComponentInstruction} from 'angular2/router'; + * + * @Component({ * selector: 'my-cmp' * }) + * @View({ + * template: '
hello!
' + * }) * class MyCmp implements CanReuse, OnReuse { - * canReuse() { + * canReuse(next: ComponentInstruction, prev: ComponentInstruction) { * return true; * } * - * onReuse(next, prev) { + * onReuse(next: ComponentInstruction, prev: ComponentInstruction) { * this.params = next.params; * } * } - * ``` + * ``` */ export interface OnReuse { onReuse(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any; } /** - * Defines route lifecycle method [onDeactivate], which is called by the router before destroying + * Defines route lifecycle method `onDeactivate`, which is called by the router before destroying * a component as part of a route change. * + * The `onDeactivate` hook is called with two {@link ComponentInstruction}s as parameters, the first + * representing the current route being navigated to, and the second parameter representing the + * previous route. + * * If `onDeactivate` returns a promise, the route change will wait until the promise settles. * * ## Example * ``` - * @Directive({ + * import {Component, View} from 'angular2/angular2'; + * import {OnDeactivate, ComponentInstruction} from 'angular2/router'; + * + * @Component({ * selector: 'my-cmp' * }) - * class MyCmp implements CanReuse, OnReuse { - * canReuse() { - * return true; - * } - * - * onReuse(next, prev) { - * this.params = next.params; + * @View({ + * template: '
hello!
' + * }) + * class MyCmp implements OnDeactivate { + * onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { + * return this.doFadeAwayAnimation(); * } * } * ``` @@ -87,24 +113,37 @@ export interface OnDeactivate { } /** - * Defines route lifecycle method [canReuse], which is called by the router to determine whether a + * Defines route lifecycle method `canReuse`, which is called by the router to determine whether a * component should be reused across routes, or whether to destroy and instantiate a new component. * - * If `canReuse` returns or resolves to `true`, the component instance will be reused. + * The `canReuse` hook is called with two {@link ComponentInstruction}s as parameters, the first + * representing the current route being navigated to, and the second parameter representing the + * previous route. + * + * If `canReuse` returns or resolves to `true`, the component instance will be reused and the + * {@link OnDeactivate} hook will be run. If `canReuse` returns or resolves to `false`, a new + * component will be instantiated, and the existing component will be deactivated and removed as + * part of the navigation. * * If `canReuse` throws or rejects, the navigation will be cancelled. * * ## Example * ``` - * @Directive({ + * import {Component, View} from 'angular2/angular2'; + * import {CanReuse, OnReuse, ComponentInstruction} from 'angular2/router'; + * + * @Component({ * selector: 'my-cmp' * }) + * @View({ + * template: '
hello!
' + * }) * class MyCmp implements CanReuse, OnReuse { - * canReuse(next, prev) { + * canReuse(next: ComponentInstruction, prev: ComponentInstruction) { * return next.params.id == prev.params.id; * } * - * onReuse(next, prev) { + * onReuse(next: ComponentInstruction, prev: ComponentInstruction) { * this.id = next.params.id; * } * } @@ -115,20 +154,32 @@ export interface CanReuse { } /** - * Defines route lifecycle method [canDeactivate], which is called by the router to determine + * Defines route lifecycle method `canDeactivate`, which is called by the router to determine * if a component can be removed as part of a navigation. * - * If `canDeactivate` returns or resolves to `false`, the navigation is cancelled. + * The `canDeactivate` hook is called with two {@link ComponentInstruction}s as parameters, the + * first representing the current route being navigated to, and the second parameter + * representing the previous route. + * + * If `canDeactivate` returns or resolves to `false`, the navigation is cancelled. If it returns or + * resolves to `true`, then the navigation continues, and the component will be deactivated + * (the {@link OnDeactivate} hook will be run) and removed. * * If `canDeactivate` throws or rejects, the navigation is also cancelled. * * ## Example * ``` - * @Directive({ + * import {Component, View} from 'angular2/angular2'; + * import {CanDeactivate, ComponentInstruction} from 'angular2/router'; + * + * @Component({ * selector: 'my-cmp' * }) + * @View({ + * template: '
hello!
' + * }) * class MyCmp implements CanDeactivate { - * canDeactivate(next, prev) { + * canDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { * return askUserIfTheyAreSureTheyWantToQuit(); * } * } diff --git a/modules/angular2/src/router/lifecycle_annotations.ts b/modules/angular2/src/router/lifecycle_annotations.ts index 0abbd95d6969..313a97d1aff4 100644 --- a/modules/angular2/src/router/lifecycle_annotations.ts +++ b/modules/angular2/src/router/lifecycle_annotations.ts @@ -17,21 +17,33 @@ export { } from './lifecycle_annotations_impl'; /** - * Defines route lifecycle method [canActivate], which is called by the router to determine + * Defines route lifecycle hook `CanActivate`, which is called by the router to determine * if a component can be instantiated as part of a navigation. * - * Note that unlike other lifecycle hooks, this one uses an annotation rather than an interface. - * This is because [canActivate] is called before the component is instantiated. + * The `CanActivate` hook is called with two {@link ComponentInstruction}s as parameters, the first + * representing + * the current route being navigated to, and the second parameter representing the previous route or + * `null`. * - * If `canActivate` returns or resolves to `false`, the navigation is cancelled. + * Note that unlike other lifecycle hooks, this one uses an annotation rather than an interface. + * This is because the `CanActivate` function is called before the component is instantiated. * - * If `canActivate` throws or rejects, the navigation is also cancelled. + * If `CanActivate` returns or resolves to `false`, the navigation is cancelled. + * If `CanActivate` throws or rejects, the navigation is also cancelled. + * If `CanActivate` returns or resolves to `true`, navigation continues, the component is + * instantiated, and the {@link OnActivate} hook of that component is called if implemented. * * ## Example * ``` - * @Directive({ + * import {Component} from 'angular2/angular2'; + * import {CanActivate} from 'angular2/router'; + * + * @Component({ * selector: 'control-panel-cmp' * }) + * @View({ + * template: '
Control Panel: ...
' + * }) * @CanActivate(() => checkIfUserIsLoggedIn()) * class ControlPanelCmp { * // ... From 65a304c610c6a17af92077ef326dfe3cb1976cd9 Mon Sep 17 00:00:00 2001 From: Brian Ford Date: Mon, 21 Sep 2015 17:17:25 -0700 Subject: [PATCH 3/4] docs(router): improve documentation for router bindings --- modules/angular2/router.ts | 108 +++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 9 deletions(-) diff --git a/modules/angular2/router.ts b/modules/angular2/router.ts index 19a2913e3a65..23cef5254ae6 100644 --- a/modules/angular2/router.ts +++ b/modules/angular2/router.ts @@ -32,33 +32,101 @@ import {Location} from './src/router/location'; import {bind, OpaqueToken, Binding} from './core'; import {CONST_EXPR, Type} from './src/core/facade/lang'; +/** + * Token used to bind the component with the top-level {@link RouteConfig}s for the + * application. + * + * You can use the {@link routerBindings} function in your {@link bootstrap} bindings to + * simplify setting up these bindings. + * + * ## Example + * + * ``` + * import {Component, View} from 'angular2/angular2'; + * import { + * ROUTER_DIRECTIVES, + * ROUTER_BINDINGS, + * ROUTER_PRIMARY_COMPONENT, + * RouteConfig + * } from 'angular2/router'; + * + * @Component({...}) + * @View({directives: [ROUTER_DIRECTIVES]}) + * @RouteConfig([ + * {...}, + * ]) + * class AppCmp { + * // ... + * } + * + * bootstrap(AppCmp, [ + * ROUTER_BINDINGS, + * bind(ROUTER_PRIMARY_COMPONENT).toValue(AppCmp) + * ]); + * ``` + */ export const ROUTER_PRIMARY_COMPONENT: OpaqueToken = CONST_EXPR(new OpaqueToken('RouterPrimaryComponent')); -export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]); - /** - * A list of {@link Binding}. To use the router, you must add this to your application. + * A list of directives. To use the router directives like {@link RouterOutlet} and + * {@link RouterLink}, add this to your `directives` array in the {@link View} decorator of your + * component. * * ## Example * - * ```typescript + * ``` + * import {Component, View} from 'angular2/angular2'; + * import {ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router'; + * * @Component({...}) * @View({directives: [ROUTER_DIRECTIVES]}) * @RouteConfig([ - * new Route(...), + * {...}, * ]) * class AppCmp { - * constructor(router: Router, location: Location) { * // ... - * } - * * } * - * * bootstrap(AppCmp, [routerBindings(AppCmp)]); * ``` */ +export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]); + +/** + * A list of {@link Binding}s. To use the router, you must add this to your application. + * + * Note that you also need to bind to {@link ROUTER_PRIMARY_COMPONENT}. + * + * You can use the {@link routerBindings} function in your {@link bootstrap} bindings to + * simplify setting up these bindings. + * + * ## Example + * + * ``` + * import {Component, View} from 'angular2/angular2'; + * import { + * ROUTER_DIRECTIVES, + * ROUTER_BINDINGS, + * ROUTER_PRIMARY_COMPONENT, + * RouteConfig + * } from 'angular2/router'; + * + * @Component({...}) + * @View({directives: [ROUTER_DIRECTIVES]}) + * @RouteConfig([ + * {...}, + * ]) + * class AppCmp { + * // ... + * } + * + * bootstrap(AppCmp, [ + * ROUTER_BINDINGS, + * bind(ROUTER_PRIMARY_COMPONENT).toValue(AppCmp) + * ]); + * ``` + */ export const ROUTER_BINDINGS: any[] = CONST_EXPR([ RouteRegistry, CONST_EXPR(new Binding(LocationStrategy, {toClass: PathLocationStrategy})), @@ -75,6 +143,28 @@ function routerFactory(registry, location, primaryComponent) { return new RootRouter(registry, location, primaryComponent); } +/** + * A list of {@link Binding}s. To use the router, you must add these bindings to + * your application. + * + * ## Example + * + * ``` + * import {Component, View} from 'angular2/angular2'; + * import {ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router'; + * + * @Component({...}) + * @View({directives: [ROUTER_DIRECTIVES]}) + * @RouteConfig([ + * {...}, + * ]) + * class AppCmp { + * // ... + * } + * + * bootstrap(AppCmp, [routerBindings(AppCmp)]); + * ``` + */ export function routerBindings(primaryComponent: Type): Array { return [ROUTER_BINDINGS, bind(ROUTER_PRIMARY_COMPONENT).toValue(primaryComponent)]; } From f5d9bd3d591b0c7579edde3abdbcc6b6c3f69e52 Mon Sep 17 00:00:00 2001 From: Brian Ford Date: Mon, 21 Sep 2015 17:31:31 -0700 Subject: [PATCH 4/4] docs(router): improve docs for Location and related classes --- .../src/router/hash_location_strategy.ts | 39 ++++++++ modules/angular2/src/router/location.ts | 89 ++++++++++++++++++- .../angular2/src/router/location_strategy.ts | 16 ++++ .../src/router/path_location_strategy.ts | 46 ++++++++++ 4 files changed, 188 insertions(+), 2 deletions(-) diff --git a/modules/angular2/src/router/hash_location_strategy.ts b/modules/angular2/src/router/hash_location_strategy.ts index 25e2c24a99d8..5c25a1b9aaef 100644 --- a/modules/angular2/src/router/hash_location_strategy.ts +++ b/modules/angular2/src/router/hash_location_strategy.ts @@ -3,6 +3,45 @@ import {Injectable} from 'angular2/src/core/di'; import {LocationStrategy} from './location_strategy'; import {EventListener, History, Location} from 'angular2/src/core/facade/browser'; +/** + * `HashLocationStrategy` is a {@link LocationStrategy} used to configure the + * {@link Location} service to represent its state in the + * [hash fragment](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) + * of the browser's URL. + * + * `HashLocationStrategy` is the default binding for {@link LocationStrategy} + * provided in {@link routerBindings} and {@link ROUTER_BINDINGS}. + * + * For instance, if you call `location.go('/foo')`, the browser's URL will become + * `example.com#/foo`. + * + * ## Example + * + * ``` + * import {Component, View} from 'angular2/angular2'; + * import { + * ROUTER_DIRECTIVES, + * routerBindings, + * RouteConfig, + * Location + * } from 'angular2/router'; + * + * @Component({...}) + * @View({directives: [ROUTER_DIRECTIVES]}) + * @RouteConfig([ + * {...}, + * ]) + * class AppCmp { + * constructor(location: Location) { + * location.go('/foo'); + * } + * } + * + * bootstrap(AppCmp, [ + * routerBindings(AppCmp) // includes binding to HashLocationStrategy + * ]); + * ``` + */ @Injectable() export class HashLocationStrategy extends LocationStrategy { private _location: Location; diff --git a/modules/angular2/src/router/location.ts b/modules/angular2/src/router/location.ts index 49c3f5a8aaa7..9bff5a80ba93 100644 --- a/modules/angular2/src/router/location.ts +++ b/modules/angular2/src/router/location.ts @@ -5,17 +5,78 @@ import {isBlank} from 'angular2/src/core/facade/lang'; import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions'; import {OpaqueToken, Injectable, Optional, Inject} from 'angular2/src/core/di'; +/** + * The `APP_BASE_HREF` token represents the base href to be used with the + * {@link PathLocationStrategy}. + * + * If you're using {@link PathLocationStrategy}, you must provide a binding to a string + * representing the URL prefix that should be preserved when generating and recognizing + * URLs. + * + * ## Example + * + * ``` + * import {Component, View} from 'angular2/angular2'; + * import {ROUTER_DIRECTIVES, routerBindings, RouteConfig} from 'angular2/router'; + * + * @Component({...}) + * @View({directives: [ROUTER_DIRECTIVES]}) + * @RouteConfig([ + * {...}, + * ]) + * class AppCmp { + * // ... + * } + * + * bootstrap(AppCmp, [ + * routerBindings(AppCmp), + * PathLocationStrategy, + * bind(APP_BASE_HREF).toValue('/my/app') + * ]); + * ``` + */ export const APP_BASE_HREF: OpaqueToken = CONST_EXPR(new OpaqueToken('appBaseHref')); /** - * This is the service that an application developer will directly interact with. + * `Location` is a service that applications can use to interact with a browser's URL. + * Depending on which {@link LocationStrategy} is used, `Location` will either persist + * to the URL's path or the URL's hash segment. + * + * Note: it's better to use {@link Router#navigate} service to trigger route changes. Use + * `Location` only if you need to interact with or create normalized URLs outside of + * routing. * - * Responsible for normalizing the URL against the application's base href. + * `Location` is responsible for normalizing the URL against the application's base href. * A normalized URL is absolute from the URL host, includes the application's base href, and has no * trailing slash: * - `/my/app/user/123` is normalized * - `my/app/user/123` **is not** normalized * - `/my/app/user/123/` **is not** normalized + * + * ## Example + * + * ``` + * import {Component, View} from 'angular2/angular2'; + * import { + * ROUTER_DIRECTIVES, + * routerBindings, + * RouteConfig, + * Location + * } from 'angular2/router'; + * + * @Component({...}) + * @View({directives: [ROUTER_DIRECTIVES]}) + * @RouteConfig([ + * {...}, + * ]) + * class AppCmp { + * constructor(location: Location) { + * location.go('/foo'); + * } + * } + * + * bootstrap(AppCmp, [routerBindings(AppCmp)]); + * ``` */ @Injectable() export class Location { @@ -36,12 +97,23 @@ export class Location { (_) => { ObservableWrapper.callNext(this._subject, {'url': this.path(), 'pop': true}); }); } + /** + * Returns the normalized URL path. + */ path(): string { return this.normalize(this.platformStrategy.path()); } + /** + * Given a string representing a URL, returns the normalized URL path. + */ normalize(url: string): string { return stripTrailingSlash(_stripBaseHref(this._baseHref, stripIndexHtml(url))); } + /** + * Given a string representing a URL, returns the normalized URL path. + * If the given URL doesn't begin with a leading slash (`'/'`), this method adds one + * before normalizing. + */ normalizeAbsolutely(url: string): string { if (!url.startsWith('/')) { url = '/' + url; @@ -49,15 +121,28 @@ export class Location { return stripTrailingSlash(_addBaseHref(this._baseHref, url)); } + /** + * Changes the browsers URL to the normalized version of the given URL, and pushes a + * new item onto the platform's history. + */ go(url: string): void { var finalUrl = this.normalizeAbsolutely(url); this.platformStrategy.pushState(null, '', finalUrl); } + /** + * Navigates forward in the platform's history. + */ forward(): void { this.platformStrategy.forward(); } + /** + * Navigates back in the platform's history. + */ back(): void { this.platformStrategy.back(); } + /** + * Subscribe to the platform's `popState` events. + */ subscribe(onNext: (value: any) => void, onThrow: (exception: any) => void = null, onReturn: () => void = null): void { ObservableWrapper.subscribe(this._subject, onNext, onThrow, onReturn); diff --git a/modules/angular2/src/router/location_strategy.ts b/modules/angular2/src/router/location_strategy.ts index 4643ff02e2ac..84d5798e1e5c 100644 --- a/modules/angular2/src/router/location_strategy.ts +++ b/modules/angular2/src/router/location_strategy.ts @@ -4,6 +4,22 @@ function _abstract() { return new BaseException('This method is abstract'); } +/** + * `LocationStrategy` is responsible for representing and reading route state + * from the the browser's URL. Angular provides two strategies: + * {@link HashLocationStrategy} (default) and {@link PathLocationStrategy}. + * + * This is used under the hood of the {@link Location} service. + * + * Applications should use the {@link Router} or {@link Location} services to + * interact with application route state. + * + * For instance, {@link HashLocationStrategy} produces URLs like + * `http://example.com#/foo`, and {@link PathLocationStrategy} produces + * `http://example.com/foo` as an equivalent URL. + * + * See these two classes for more. + */ export class LocationStrategy { path(): string { throw _abstract(); } pushState(ctx: any, title: string, url: string): void { throw _abstract(); } diff --git a/modules/angular2/src/router/path_location_strategy.ts b/modules/angular2/src/router/path_location_strategy.ts index 42525a403230..7d634d33b1da 100644 --- a/modules/angular2/src/router/path_location_strategy.ts +++ b/modules/angular2/src/router/path_location_strategy.ts @@ -3,6 +3,52 @@ import {Injectable} from 'angular2/src/core/di'; import {EventListener, History, Location} from 'angular2/src/core/facade/browser'; import {LocationStrategy} from './location_strategy'; +/** + * `PathLocationStrategy` is a {@link LocationStrategy} used to configure the + * {@link Location} service to represent its state in the + * [path](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) of the + * browser's URL. + * + * If you're using `PathLocationStrategy`, you must provide a binding for + * {@link APP_BASE_HREF} to a string representing the URL prefix that should + * be preserved when generating and recognizing URLs. + * + * For instance, if you provide an `APP_BASE_HREF` of `'/my/app'` and call + * `location.go('/foo')`, the browser's URL will become + * `example.com/my/app/foo`. + * + * ## Example + * + * ``` + * import {Component, View, bind} from 'angular2/angular2'; + * import { + * APP_BASE_HREF + * ROUTER_DIRECTIVES, + * routerBindings, + * RouteConfig, + * Location, + * LocationStrategy, + * PathLocationStrategy + * } from 'angular2/router'; + * + * @Component({...}) + * @View({directives: [ROUTER_DIRECTIVES]}) + * @RouteConfig([ + * {...}, + * ]) + * class AppCmp { + * constructor(location: Location) { + * location.go('/foo'); + * } + * } + * + * bootstrap(AppCmp, [ + * routerBindings(AppCmp), + * bind(LocationStrategy).toClass(PathLocationStrategy), + * bind(APP_BASE_HREF).toValue('/my/app') + * ]); + * ``` + */ @Injectable() export class PathLocationStrategy extends LocationStrategy { private _location: Location;