docs(router): add api docs

This commit is contained in:
vsavkin 2016-06-28 14:49:29 -07:00
parent 0961bd1eff
commit 296a447e3c
12 changed files with 466 additions and 70 deletions

View File

@ -63,7 +63,7 @@ export function setupRouterInitializer(injector: Injector) {
}
/**
* A list of {@link Provider}s. To use the router, you must add this to your application.
* An array of {@link Provider}s. To use the router, you must add this to your application.
*
* ### Example
*
@ -73,14 +73,14 @@ export function setupRouterInitializer(injector: Injector) {
* // ...
* }
*
* const router = [
* {path: '/home', component: Home}
* const config = [
* {path: 'home', component: Home}
* ];
*
* bootstrap(AppCmp, [provideRouter(router)]);
* bootstrap(AppCmp, [provideRouter(config)]);
* ```
*
* @experimental
* @stable
*/
export function provideRouter(_config: RouterConfig, _opts: ExtraOptions): any[] {
return [

View File

@ -9,27 +9,247 @@
import {Type} from '@angular/core';
/**
* @experimental
* `RouterConfig` is an array of route configurations. Each one has the following properties:
*
* - *`path`* is a string that uses the route matcher DSL.
* - `pathMatch` is a string that specifies the matching strategy.
* - `component` is a component type.
* - `redirectTo` is the url fragment which will replace the current matched segment.
* - `outlet` is the name of the outlet the component should be placed into.
* - `canActivate` is an array of DI tokens used to look up CanActivate handlers. See {@link
* CanActivate} for more info.
* - `canDeactivate` is an array of DI tokens used to look up CanDeactivate handlers. See {@link
* CanDeactivate} for more info.
* - `data` is additional data provided to the component via `ActivatedRoute`.
* - `resolve` is a map of DI tokens used to look up data resolvers. See {@link Resolve} for more
* info.
* - `children` is an array of child route definitions.
*
* ### Simple Configuration
*
* ```
* [{
* path: 'team/:id',
* component: Team,
* children: [
* {
* path: 'user/:name',
* component: User
* }
* ]
* }]
* ```
*
* When navigating to `/team/11/user/bob`, the router will create the team component with the user
* component in it.
*
* ### Multiple Outlets
*
* ```
* [{
* path: 'team/:id',
* component: Team
* },
* {
* path: 'chat/:user',
* component: Chat
* outlet: aux
* }]
* ```
*
* When navigating to `/team/11(aux:chat/jim)`, the router will create the team component next to
* the chat component. The chat component will be placed into the aux outlet.
*
* ### Wild Cards
*
* ```
* [{
* path: '**',
* component: Sink
* }]
* ```
*
* Regardless of where you navigate to, the router will instantiate the sink component.
*
* ### Redirects
*
* ```
* [{
* path: 'team/:id',
* component: Team,
* children: [
* {
* path: 'legacy/user/:name',
* redirectTo: 'user/:name'
* },
* {
* path: 'user/:name',
* component: User
* }
* ]
* }]
* ```
*
* When navigating to '/team/11/legacy/user/jim', the router will change the url to
* '/team/11/user/jim', and then will instantiate the team component with the user component
* in it.
*
* If the `redirectTo` value starts with a '/', then it is a global redirect. E.g., if in the
* example above we change the `redirectTo` to `/user/:name`, the result url will be '/user/jim'.
*
* ### Empty Path
*
* Empty-path route configurations can be used to instantiate components that do not "consume"
* any url segments. Let's look at the following configuration:
*
* ```
* [{
* path: 'team/:id',
* component: Team,
* children: [
* {
* path: '',
* component: AllUsers
* },
* {
* path: 'user/:name',
* component: User
* }
* ]
* }]
* ```
*
* When navigating to `/team/11`, the router will instantiate the AllUsers component.
*
* Empty-path routes can have children.
*
* ```
* [{
* path: 'team/:id',
* component: Team,
* children: [
* {
* path: '',
* component: WrapperCmp,
* children: [
* {
* path: 'user/:name',
* component: User
* }
* ]
* }
* ]
* }]
* ```
*
* When navigating to `/team/11/user/jim`, the router will instantiate the wrapper component with
* the user component in it.
*
* ### Matching Strategy
*
* By default the router will look at what is left in the url, and check if it starts with
* the specified path (e.g., `/team/11/user` starts with `team/:id`).
*
* We can change the matching strategy to make sure that the path covers the whole unconsumed url,
* which is akin to `unconsumedUrl === path` or `$` regular expressions.
*
* This is particularly important when redirecting empty-path routes.
*
* ```
* [{
* path: '',
* pathMatch: 'prefix', //default
* redirectTo: 'main'
* },
* {
* path: 'main',
* component: Main
* }]
* ```
*
* Since an empty path is a prefix of any url, even when navigating to '/main', the router will
* still apply the redirect.
*
* If `pathMatch: full` is provided, the router will apply the redirect if and only if navigating to
* '/'.
*
* ```
* [{
* path: '',
* pathMatch: 'full',
* redirectTo: 'main'
* },
* {
* path: 'main',
* component: Main
* }]
* ```
*
* ### Componentless Routes
*
* It is useful at times to have the ability to share parameters between sibling components.
*
* Say we have two components--ChildCmp and AuxCmp--that we want to put next to each other and both
* of them require some id parameter.
*
* One way to do that would be to have a bogus parent component, so both the siblings can get the id
* parameter from it. This is not ideal. Instead, you can use a componentless route.
*
* ```
* [{
* path: 'parent/:id',
* children: [
* { path: 'a', component: MainChild },
* { path: 'b', component: AuxChild, outlet: 'aux' }
* ]
* }]
* ```
*
* So when navigating to `parent/10/(a//aux:b)`, the route will instantiate the main child and aux
* child components next to each other. In this example, the application component
* has to have the primary and aux outlets defined.
*
* The router will also merge the `params`, `data`, and `resolve` of the componentless parent into
* the `params`, `data`, and `resolve` of the children.
*
* This is especially useful when child components are defined as follows:
*
* ```
* [{
* path: 'parent/:id',
* children: [
* { path: '', component: MainChild },
* { path: '', component: AuxChild, outlet: 'aux' }
* ]
* }]
* ```
*
* With this configuration in place, navigating to '/parent/10' will create the main child and aux
* components.
*
* @stable
*/
export type RouterConfig = Route[];
/**
* @experimental
* See {@link RouterConfig} for more details.
* @stable
*/
export type Data = {
[name: string]: any
};
/**
* @experimental
* See {@link RouterConfig} for more details.
* @stable
*/
export type ResolveData = {
[name: string]: any
};
/**
* @experimental
* See {@link RouterConfig} for more details.
* @stable
*/
export interface Route {
path?: string;
@ -40,13 +260,13 @@ export interface Route {
terminal?: boolean;
pathMatch?: 'full'|'prefix';
component?: Type|string;
redirectTo?: string;
outlet?: string;
canActivate?: any[];
canDeactivate?: any[];
redirectTo?: string;
children?: Route[];
data?: Data;
resolve?: ResolveData;
children?: Route[];
}
export function validateConfig(config: RouterConfig): void {

View File

@ -13,32 +13,46 @@ import {Router} from '../router';
import {ActivatedRoute} from '../router_state';
import {UrlTree} from '../url_tree';
/**
* The RouterLink directive lets you link to specific parts of your app.
*
* Consider the following route configuration:
* ```
* [{ path: '/user', component: UserCmp }]
* [{ path: 'user/:name', component: UserCmp }]
* ```
*
* When linking to this `User` route, you can write:
*
* ```
* <a [routerLink]="['/user']">link to user component</a>
* <a [routerLink]="/user/bob">link to user component</a>
* ```
*
* RouterLink expects the value to be an array of path segments, followed by the params
* for that level of routing. For instance `['/team', {teamId: 1}, 'user', {userId: 2}]`
* means that we want to generate a link to `/team;teamId=1/user;userId=2`.
* If you use dynamic values to generate the link, you can pass an array of path
* segments, followed by the params for each segment.
*
* The first segment name can be prepended with `/`, `./`, or `../`.
* If the segment begins with `/`, the router will look up the route from the root of the app.
* If the segment begins with `./`, or doesn't begin with a slash, the router will
* instead look in the current component's children for the route.
* And if the segment begins with `../`, the router will go up one level.
* For instance `['/team', teamId, 'user', userName, {details: true}]`
* means that we want to generate a link to `/team/11/user/bob;details=true`.
* Multiple static segments can be merged into one (e.g., `['/team/11/user', userName, {details:
true}]`).
*
* The first segment name can be prepended with `/`, `./`, or `../`:
* * If the first segment begins with `/`, the router will look up the route from the root of the
app.
* * If the first segment begins with `./`, or doesn't begin with a slash, the router will
* instead look in the children of the current activated route.
* * And if the first segment begins with `../`, the router will go up one level.
*
* You can set query params and fragment as follows:
*
* ```
* <a [routerLink]="['/user/bob']" [queryParams]="{debug: true}" fragment="education">link to user
component</a>
* ```
*
* RouterLink will use these to generate this link: `/user/bob#education?debug=true`.
*
* @stable
*/
@Directive({selector: '[routerLink]'})
export class RouterLink implements OnChanges {

View File

@ -14,17 +14,55 @@ import {containsTree} from '../url_tree';
import {RouterLink} from './router_link';
interface RouterLinkActiveOptions {
exact: boolean;
}
/**
* The RouterLinkActive directive lets you add a CSS class to an element when the link's route
* becomes active.
*
* Consider the following example:
*
* ```
* <a [routerLink]="/user/bob" routerLinkActive="active-link">Bob</a>
* ```
*
* When the url is either '/user' or '/user/bob', the active-link class will
* be added to the `a` tag. If the url changes, the class will be removed.
*
* You can set more than one class, as follows:
*
* ```
* <a [routerLink]="/user/bob" routerLinkActive="class1 class2">Bob</a>
* <a [routerLink]="/user/bob" routerLinkActive="['class1', 'class2']">Bob</a>
* ```
*
* You can configure RouterLinkActive by passing `exact: true`. This will add the classes
* only when the url matches the link exactly.
*
* ```
* <a [routerLink]="/user/bob" routerLinkActive="active-link" [routerLinkActiveOptions]="{exact:
* true}">Bob</a>
* ```
*
* Finally, you can apply the RouterLinkActive directive to an ancestor of a RouterLink.
*
* ```
* <div routerLinkActive="active-link" [routerLinkActiveOptions]="{exact: true}">
* <a [routerLink]="/user/jim">Jim</a>
* <a [routerLink]="/user/bob">Bob</a>
* </div>
* ```
*
* This will set the active-link class on the div tag if the url is either '/user/jim' or
* '/user/bob'.
*
* @stable
*/
@Directive({selector: '[routerLinkActive]'})
export class RouterLinkActive implements OnChanges, OnDestroy, AfterContentInit {
@ContentChildren(RouterLink) private links: QueryList<RouterLink>;
private classes: string[] = [];
private subscription: Subscription;
@Input() private routerLinkActiveOptions: RouterLinkActiveOptions = {exact: false};
@Input() private routerLinkActiveOptions: {exact: boolean} = {exact: false};
/**
* @internal

View File

@ -12,6 +12,19 @@ import {RouterOutletMap} from '../router_outlet_map';
import {ActivatedRoute} from '../router_state';
import {PRIMARY_OUTLET} from '../shared';
/**
* A router outlet is a placeholder that Angular dynamically fills based on the application's route.
*
* ## Use
*
* ```
* <router-outlet></router-outlet>
* <router-outlet name="left"></router-outlet>
* <router-outlet name="right"></router-outlet>
* ```
*
* @stable
*/
@Directive({selector: 'router-outlet'})
export class RouterOutlet {
private activated: ComponentRef<any>;
@ -61,8 +74,10 @@ export class RouterOutlet {
} catch (e) {
if (!(e instanceof NoComponentFactoryError)) throw e;
const componentName = component ? component.name : null;
console.warn(
`No component factory found for '${componentName}'. Add '${componentName}' to the 'precompile' list of your application component. This will be required in a future release of the router.`);
`'${componentName}' not found in precompile array. To ensure all components referred to by the RouterConfig are compiled, you must add '${componentName}' to the 'precompile' array of your application component. This will be required in a future release of the router.`);
factory = snapshot._resolvedComponentFactory;
}

View File

@ -12,7 +12,43 @@ import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
/**
* An interface a class can implement to be a guard deciding if a route can be activated.
*
* @experimental
* ### Example
*
* ```
* class CanActivateTeam implements CanActivate {
* constructor(private permissions: Permissions, private currentUser: UserToken) {}
*
* canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> {
* return this.permissions.canActivate(this.currentUser, this.route.params.id);
* }
* }
*
* bootstrap(AppComponent, [
* CanActivateTeam,
*
* provideRouter([{
* path: 'team/:id',
* component: Team,
* canActivate: [CanActivateTeam]
* }])
* );
* ```
*
* You can also provide a function with the same signature instead of the class:
*
* ```
* bootstrap(AppComponent, [
* {provide: 'canActivateTeam', useValue: (route: ActivatedRouteSnapshot, state:
* RouterStateSnapshot) => true},
* provideRouter([{
* path: 'team/:id',
* component: Team,
* canActivate: ['canActivateTeam']
* }])
* );
* ```
*
* @stable
*/
export interface CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
@ -22,7 +58,43 @@ export interface CanActivate {
/**
* An interface a class can implement to be a guard deciding if a route can be deactivated.
*
* @experimental
* ### Example
*
* ```
* class CanDeactivateTeam implements CanDeactivate {
* constructor(private permissions: Permissions, private currentUser: UserToken) {}
*
* canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> {
* return this.permissions.canDeactivate(this.currentUser, this.route.params.id);
* }
* }
*
* bootstrap(AppComponent, [
* CanDeactivateTeam,
*
* provideRouter([{
* path: 'team/:id',
* component: Team,
* canDeactivate: [CanDeactivateTeam]
* }])
* );
* ```
*
* You can also provide a function with the same signature instead of the class:
*
* ```
* bootstrap(AppComponent, [
* {provide: 'canDeactivateTeam', useValue: (route: ActivatedRouteSnapshot, state:
* RouterStateSnapshot) => true},
* provideRouter([{
* path: 'team/:id',
* component: Team,
* canActivate: ['canDeactivateTeam']
* }])
* );
* ```
*
* @stable
*/
export interface CanDeactivate<T> {
canDeactivate(component: T, route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
@ -30,6 +102,34 @@ export interface CanDeactivate<T> {
}
/**
* An interface a class can implement to be a data provider.
*
* ### Example
*
* ```
* class TeamResolver implements Resolve {
* constructor(private backend: Backend) {}
*
* resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<any> {
* return this.backend.fetchTeam(this.route.params.id);
* }
* }
*
* bootstrap(AppComponent, [
* TeamResolver,
*
* provideRouter([{
* path: 'team/:id',
* component: TeamCmp,
* resolve: {
* team: TeamResolver
* }
* }])
* );
* ```
*
* You can also provide a function with the same signature instead of the class.
*
* @experimental
*/
export interface Resolve<T> {

View File

@ -44,7 +44,7 @@ export interface NavigationExtras {
/**
* An event triggered when a navigation starts
*
* @experimental
* @stable
*/
export class NavigationStart {
constructor(public id: number, public url: string) {}
@ -55,7 +55,7 @@ export class NavigationStart {
/**
* An event triggered when a navigation ends successfully
*
* @experimental
* @stable
*/
export class NavigationEnd {
constructor(public id: number, public url: string, public urlAfterRedirects: string) {}
@ -68,7 +68,7 @@ export class NavigationEnd {
/**
* An event triggered when a navigation is canceled
*
* @experimental
* @stable
*/
export class NavigationCancel {
constructor(public id: number, public url: string) {}
@ -79,7 +79,7 @@ export class NavigationCancel {
/**
* An event triggered when a navigation fails due to unexpected error
*
* @experimental
* @stable
*/
export class NavigationError {
constructor(public id: number, public url: string, public error: any) {}
@ -92,7 +92,7 @@ export class NavigationError {
/**
* An event triggered when routes are recognized
*
* @experimental
* @stable
*/
export class RoutesRecognized {
constructor(
@ -105,14 +105,16 @@ export class RoutesRecognized {
}
/**
* @experimental
* @stable
*/
export type Event = NavigationStart | NavigationEnd | NavigationCancel | NavigationError;
/**
* The `Router` is responsible for mapping URLs to components.
*
* @experimental
* See {@link RouterConfig) for more details and examples.
*
* @stable
*/
export class Router {
private currentUrlTree: UrlTree;

View File

@ -9,7 +9,7 @@
import {RouterOutlet} from './directives/router_outlet';
/**
* @experimental
* @stable
*/
export class RouterOutletMap {
/** @internal */

View File

@ -25,10 +25,10 @@ import {RouterConfig} from './config';
* }
*
* const router = [
* {path: '/home', component: Home}
* {path: 'home', component: Home}
* ];
*
* bootstrap(AppCmp, [provideRouter(router)]);
* bootstrap(AppCmp, [provideRouter(router, {enableTracing: true})]);
* ```
*
* @experimental

View File

@ -32,7 +32,7 @@ import {Tree, TreeNode} from './utils/tree';
* }
* ```
*
* @experimental
* @stable
*/
export class RouterState extends Tree<ActivatedRoute> {
/**
@ -75,8 +75,7 @@ function createEmptyStateSnapshot(urlTree: UrlTree, rootComponent: Type): Router
/**
* Contains the information about a component loaded in an outlet. The information is provided
* through
* the params and urlSegments observables.
* through the params, urlSegments, and data observables.
*
* ### Usage
*
@ -84,11 +83,12 @@ function createEmptyStateSnapshot(urlTree: UrlTree, rootComponent: Type): Router
* class MyComponent {
* constructor(route: ActivatedRoute) {
* const id: Observable<string> = route.params.map(p => p.id);
* const data = route.data.map(d => d.user); //includes `data` and `resolve`
* }
* }
* ```
*
* @experimental
* @stable
*/
export class ActivatedRoute {
/** @internal */
@ -110,6 +110,9 @@ export class ActivatedRoute {
}
}
/**
* @internal
*/
export class InheritedResolve {
/**
* @internal
@ -138,11 +141,12 @@ export class InheritedResolve {
* class MyComponent {
* constructor(route: ActivatedRoute) {
* const id: string = route.snapshot.params.id;
* const data = route.snapshot.data;
* }
* }
* ```
*
* @experimental
* @stable
*/
export class ActivatedRouteSnapshot {
/**
@ -195,7 +199,7 @@ export class ActivatedRouteSnapshot {
* }
* ```
*
* @experimental
* @stable
*/
export class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> {
/**

View File

@ -63,7 +63,7 @@ function containsSegmentHelper(
/**
* A URL in the tree form.
*
* @experimental
* @stable
*/
export class UrlTree {
/**
@ -76,6 +76,9 @@ export class UrlTree {
toString(): string { return new DefaultUrlSerializer().serialize(this); }
}
/**
* @stable
*/
export class UrlSegment {
/**
* @internal
@ -100,7 +103,7 @@ export class UrlSegment {
/**
* @experimental
* @stable
*/
export class UrlPathWithParams {
constructor(public path: string, public parameters: {[key: string]: string}) {}

View File

@ -1,4 +1,4 @@
/** @experimental */
/** @stable */
export declare class ActivatedRoute {
component: Type | string;
data: Observable<Data>;
@ -9,7 +9,7 @@ export declare class ActivatedRoute {
toString(): string;
}
/** @experimental */
/** @stable */
export declare class ActivatedRouteSnapshot {
component: Type | string;
data: Data;
@ -19,17 +19,17 @@ export declare class ActivatedRouteSnapshot {
toString(): string;
}
/** @experimental */
/** @stable */
export interface CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean;
}
/** @experimental */
/** @stable */
export interface CanDeactivate<T> {
canDeactivate(component: T, route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean;
}
/** @experimental */
/** @stable */
export declare type Data = {
[name: string]: any;
};
@ -40,7 +40,7 @@ export declare class DefaultUrlSerializer implements UrlSerializer {
serialize(tree: UrlTree): string;
}
/** @experimental */
/** @stable */
export declare type Event = NavigationStart | NavigationEnd | NavigationCancel | NavigationError;
/** @experimental */
@ -48,7 +48,7 @@ export interface ExtraOptions {
enableTracing?: boolean;
}
/** @experimental */
/** @stable */
export declare class NavigationCancel {
id: number;
url: string;
@ -56,7 +56,7 @@ export declare class NavigationCancel {
toString(): string;
}
/** @experimental */
/** @stable */
export declare class NavigationEnd {
id: number;
url: string;
@ -65,7 +65,7 @@ export declare class NavigationEnd {
toString(): string;
}
/** @experimental */
/** @stable */
export declare class NavigationError {
error: any;
id: number;
@ -74,7 +74,7 @@ export declare class NavigationError {
toString(): string;
}
/** @experimental */
/** @stable */
export declare class NavigationStart {
id: number;
url: string;
@ -98,18 +98,18 @@ export interface Resolve<T> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | any;
}
/** @experimental */
/** @stable */
export declare type ResolveData = {
[name: string]: any;
};
/** @experimental */
/** @stable */
export interface Route {
path?: string;
pathMatch?:
/** @deprecated */ terminal?: boolean;
/** @experimental */
/** @stable */
export declare class Router {
events: Observable<Event>;
routerState: RouterState;
@ -125,15 +125,15 @@ export declare class Router {
/** @experimental */
export declare const ROUTER_DIRECTIVES: (typeof RouterOutlet | typeof RouterLink | typeof RouterLinkActive)[];
/** @experimental */
/** @stable */
export declare type RouterConfig = Route[];
/** @experimental */
/** @stable */
export declare class RouterOutletMap {
registerOutlet(name: string, outlet: RouterOutlet): void;
}
/** @experimental */
/** @stable */
export declare class RouterState extends Tree<ActivatedRoute> {
fragment: Observable<string>;
queryParams: Observable<Params>;
@ -141,7 +141,7 @@ export declare class RouterState extends Tree<ActivatedRoute> {
toString(): string;
}
/** @experimental */
/** @stable */
export declare class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> {
fragment: string;
queryParams: Params;
@ -149,7 +149,7 @@ export declare class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> {
toString(): string;
}
/** @experimental */
/** @stable */
export declare class RoutesRecognized {
id: number;
state: RouterStateSnapshot;
@ -159,7 +159,7 @@ export declare class RoutesRecognized {
toString(): string;
}
/** @experimental */
/** @stable */
export declare class UrlPathWithParams {
parameters: {
[key: string]: string;
@ -177,7 +177,7 @@ export declare abstract class UrlSerializer {
abstract serialize(tree: UrlTree): string;
}
/** @experimental */
/** @stable */
export declare class UrlTree {
fragment: string;
queryParams: {