From 32564ece271ea188a9d17115abc77d2ed6d5e5fc Mon Sep 17 00:00:00 2001 From: vsavkin Date: Sat, 10 Sep 2016 16:53:09 -0700 Subject: [PATCH] docs(router): update RouterState docs --- modules/@angular/router/src/router_state.ts | 197 +++++++++++++++++--- modules/@angular/router/src/shared.ts | 3 +- modules/@angular/router/src/url_tree.ts | 133 ++++++++++++- 3 files changed, 297 insertions(+), 36 deletions(-) diff --git a/modules/@angular/router/src/router_state.ts b/modules/@angular/router/src/router_state.ts index 0b70de9161..94a4f1338c 100644 --- a/modules/@angular/router/src/router_state.ts +++ b/modules/@angular/router/src/router_state.ts @@ -18,28 +18,42 @@ import {Tree, TreeNode} from './utils/tree'; /** - * The state of the router. + * @whatItDoes Represents the state of the router. * - * ### Usage + * @howToUse * * ``` - * @Component({template:''}) + * @Component({templateUrl:'template.html'}) * class MyComponent { * constructor(router: Router) { - * const state = router.routerState; - * const id: Observable = state.root.firstChild.params.map(p => p.id); - * const isDebug: Observable = state.root.queryParams.map(q => q.debug); + * const state: RouterState = router.routerState; + * const root: ActivatedRoute = state.root; + * const child = root.firstChild; + * const id: Observable = child.params.map(p => p.id); + * //... * } * } * ``` * + * @description + * RouterState is a tree of activated routes. Every node in this tree knows about the "consumed" URL + * segments, + * the extracted parameters, and the resolved data. + * + * See {@link ActivatedRoute} for more information. + * * @stable */ export class RouterState extends Tree { /** * @internal */ - constructor(root: TreeNode, public snapshot: RouterStateSnapshot) { + constructor( + root: TreeNode, + /** + * The current snapshot of the router state. + */ + public snapshot: RouterStateSnapshot) { super(root); setRouterStateSnapshot(this, root); } @@ -74,17 +88,19 @@ export function createEmptyStateSnapshot( } /** - * Contains the information about a component loaded in an outlet. The information is provided - * through the params, urlSegments, and data observables. + * @whatItDoes Contains the information about a route associated with a component loaded in an + * outlet. + * ActivatedRoute can also be used to traverse the router state tree. * - * ### Usage + * @howToUse * * ``` - * @Component({template:''}) + * @Component({templateUrl:'./my-component.html'}) * class MyComponent { * constructor(route: ActivatedRoute) { * const id: Observable = route.params.map(p => p.id); - * const data = route.data.map(d => d.user); //includes `data` and `resolve` + * const url: Observable = route.url.map(s => s.join('')); + * const user = route.data.map(d => d.user); //includes `data` and `resolve` * } * } * ``` @@ -94,6 +110,10 @@ export function createEmptyStateSnapshot( export class ActivatedRoute { /** @internal */ _futureSnapshot: ActivatedRouteSnapshot; + + /** + * The current snapshot of this route. + */ snapshot: ActivatedRouteSnapshot; /** @internal */ @@ -103,25 +123,82 @@ export class ActivatedRoute { * @internal */ constructor( - public url: Observable, public params: Observable, - public queryParams: Observable, public fragment: Observable, - public data: Observable, public outlet: string, public component: Type|string, + /** + * The URL segments matched by this route. The observable will emit a new value when + * the array of segments changes. + */ + public url: Observable, + + /** + * The matrix parameters scoped to this route. The observable will emit a new value when + * the set of the parameters changes. + */ + public params: Observable, + + /** + * The query parameters shared by all the routes. The observable will emit a new value when + * the set of the parameters changes. + */ + public queryParams: Observable, + + /** + * The URL fragment shared by all the routes. The observable will emit a new value when + * the URL fragment changes. + */ + public fragment: Observable, + + /** + * The static and resolved data of this route. The observable will emit a new value when + * any of the resolvers returns a new object. + */ + public data: Observable, + + /** + * The outlet name of the route. It's a constant. + */ + public outlet: string, + + /** + * The component of the route. It's a constant. + */ + public component: Type|string, // TODO: vsavkin: remove |string futureSnapshot: ActivatedRouteSnapshot) { this._futureSnapshot = futureSnapshot; } + /** + * The configuration used to match this route. + */ get routeConfig(): Route { return this._futureSnapshot.routeConfig; } + /** + * The root of the router state. + */ get root(): ActivatedRoute { return this._routerState.root; } + /** + * The parent of this route in the router state tree. + */ get parent(): ActivatedRoute { return this._routerState.parent(this); } + /** + * The first child of this route in the router state tree. + */ get firstChild(): ActivatedRoute { return this._routerState.firstChild(this); } + /** + * The children of this route in the router state tree. + */ get children(): ActivatedRoute[] { return this._routerState.children(this); } + /** + * The path from the root of the router state tree to this route. + */ get pathFromRoot(): ActivatedRoute[] { return this._routerState.pathFromRoot(this); } + /** + * @docsNotRequired + */ toString(): string { return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`; } @@ -150,16 +227,20 @@ export class InheritedResolve { } /** - * Contains the information about a component loaded in an outlet at a particular moment in time. + * @whatItDoes Contains the information about a route associated with a component loaded in an + * outlet + * at a particular moment in time. ActivatedRouteSnapshot can also be used to traverse the router + * state tree. * - * ### Usage + * @howToUse * * ``` - * @Component({template:''}) + * @Component({templateUrl:'./my-component.html'}) * class MyComponent { * constructor(route: ActivatedRoute) { * const id: string = route.snapshot.params.id; - * const data = route.snapshot.data; + * const url: string = route.snapshot.url.join(''); + * const user = route.snapshot.data.user; * } * } * ``` @@ -186,8 +267,39 @@ export class ActivatedRouteSnapshot { * @internal */ constructor( - public url: UrlSegment[], public params: Params, public queryParams: Params, - public fragment: string, public data: Data, public outlet: string, + /** + * The URL segments matched by this route. + */ + public url: UrlSegment[], + + /** + * The matrix parameters scoped to this route. + */ + public params: Params, + + /** + * The query parameters shared by all the routes. + */ + public queryParams: Params, + + /** + * The URL fragment shared by all the routes. + */ + public fragment: string, + + /** + * The static and resolved data of this route. + */ + public data: Data, + + /** + * The outlet name of the route. + */ + public outlet: string, + + /** + * The component of the route. + */ public component: Type|string, routeConfig: Route, urlSegment: UrlSegmentGroup, lastPathIndex: number, resolve: InheritedResolve) { this._routeConfig = routeConfig; @@ -196,18 +308,39 @@ export class ActivatedRouteSnapshot { this._resolve = resolve; } + /** + * The configuration used to match this route. + */ get routeConfig(): Route { return this._routeConfig; } + /** + * The root of the router state. + */ get root(): ActivatedRouteSnapshot { return this._routerState.root; } + /** + * The parent of this route in the router state tree. + */ get parent(): ActivatedRouteSnapshot { return this._routerState.parent(this); } + /** + * The first child of this route in the router state tree. + */ get firstChild(): ActivatedRouteSnapshot { return this._routerState.firstChild(this); } + /** + * The children of this route in the router state tree. + */ get children(): ActivatedRouteSnapshot[] { return this._routerState.children(this); } + /** + * The path from the root of the router state tree to this route. + */ get pathFromRoot(): ActivatedRouteSnapshot[] { return this._routerState.pathFromRoot(this); } + /** + * @docsNotRequired + */ toString(): string { const url = this.url.map(s => s.toString()).join('/'); const matched = this._routeConfig ? this._routeConfig.path : ''; @@ -216,26 +349,38 @@ export class ActivatedRouteSnapshot { } /** - * The state of the router at a particular moment in time. + * @whatItDoes Represents the state of the router at a moment in time. * - * ### Usage + * @howToUse * * ``` - * @Component({template:''}) + * @Component({templateUrl:'template.html'}) * class MyComponent { * constructor(router: Router) { - * const snapshot = router.routerState.snapshot; + * const state: RouterState = router.routerState; + * const snapshot: RouterStateSnapshot = state.snapshot; + * const root: ActivatedRouteSnapshot = snapshot.root; + * const child = root.firstChild; + * const id: Observable = child.params.map(p => p.id); + * //... * } * } * ``` * + * @description + * RouterStateSnapshot is a tree of activated route snapshots. Every node in this tree knows about + * the "consumed" URL segments, the extracted parameters, and the resolved data. + * * @stable */ export class RouterStateSnapshot extends Tree { /** * @internal */ - constructor(public url: string, root: TreeNode) { + constructor( + + /** The url from which this snapshot was created */ + public url: string, root: TreeNode) { super(root); setRouterStateSnapshot(this, root); } diff --git a/modules/@angular/router/src/shared.ts b/modules/@angular/router/src/shared.ts index 2b45aceb2e..de5506aa2d 100644 --- a/modules/@angular/router/src/shared.ts +++ b/modules/@angular/router/src/shared.ts @@ -7,8 +7,7 @@ */ /** - * Name of the primary outlet. - * @type {string} + * @whatItDoes Name of the primary outlet. * * @stable */ diff --git a/modules/@angular/router/src/url_tree.ts b/modules/@angular/router/src/url_tree.ts index 14554051ba..78eb7a27b1 100644 --- a/modules/@angular/router/src/url_tree.ts +++ b/modules/@angular/router/src/url_tree.ts @@ -61,7 +61,31 @@ function containsSegmentGroupHelper( } /** - * A URL in the tree form. + * @whatItDoes Represents the parsed URL. + * + * @howToUse + * + * ``` + * @Component({templateUrl:'template.html'}) + * class MyComponent { + * constructor(router: Router) { + * const tree: UrlTree = + * router.parseUrl('/team/33/(user/victor//support:help)?debug=true#fragment'); + * const f = tree.fragment; // return 'fragment' + * const q = tree.queryParams; // returns {debug: 'true'} + * const g: UrlSegmentGroup = tree.root.children[PRIMARY_OUTLET]; + * const s: UrlSegment[] = g.segments; // returns 2 segments 'team' and '33' + * g.children[PRIMARY_OUTLET].segments; // returns 2 segments 'user' and 'victor' + * g.children['support'].segments; // return 1 segment 'help' + * } + * } + * ``` + * + * @description + * + * Since a router state is a tree, and the URL is nothing but a serialized state, the URL is a + * serialized tree. + * UrlTree is a data structure that provides a lot of affordances in dealing with URLs * * @stable */ @@ -70,13 +94,30 @@ export class UrlTree { * @internal */ constructor( - public root: UrlSegmentGroup, public queryParams: {[key: string]: string}, + /** + * The root segment group of the URL tree. + */ + public root: UrlSegmentGroup, + /** + * The query params of the URL. + */ + public queryParams: {[key: string]: string}, + /** + * The fragment of the URL. + */ public fragment: string) {} + /** + * @docsNotRequired + */ toString(): string { return new DefaultUrlSerializer().serialize(this); } } /** + * @whatItDoes Represents the parsed URL segment. + * + * See {@link UrlTree} for more information. + * * @stable */ export class UrlSegmentGroup { @@ -90,8 +131,22 @@ export class UrlSegmentGroup { */ _segmentIndexShift: number; + /** + * The parent node in the url tree. + */ public parent: UrlSegmentGroup = null; - constructor(public segments: UrlSegment[], public children: {[key: string]: UrlSegmentGroup}) { + + constructor( + /** + * The URL segments of this group. See {@link UrlSegment} for more information. + */ + public segments: UrlSegment[], + /** + * The list of children of this group. + */ + public children: {[key: string]: UrlSegmentGroup} + + ) { forEach(children, (v: any, k: any) => v.parent = this); } @@ -105,15 +160,53 @@ export class UrlSegmentGroup { */ get numberOfChildren(): number { return Object.keys(this.children).length; } + /** + * @docsNotRequired + */ toString(): string { return serializePaths(this); } } /** + * @whatItDoes Represents a single URL segment. + * + * @howToUse + * + * ``` + * @Component({templateUrl:'template.html'}) + * class MyComponent { + * constructor(router: Router) { + * const tree: UrlTree = router.parseUrl('/team;id=33'); + * const g: UrlSegmentGroup = tree.root.children[PRIMARY_OUTLET]; + * const s: UrlSegment[] = g.segments; + * s[0].path; // returns 'team' + * s[0].parameters; // returns {id: 33} + * } + * } + * ``` + * + * @description + * + * A UrlSegment is a part of a URL between the two slashes. It contains a path and + * the matrix parameters associated with the segment. + * * @stable */ export class UrlSegment { - constructor(public path: string, public parameters: {[key: string]: string}) {} + constructor( + /** + * The part part of a URL segment. + */ + public path: string, + + /** + * The matrix parameters associated with a segment. + */ + public parameters: {[key: string]: string}) {} + + /** + * @docsNotRequired + */ toString(): string { return serializePath(this); } } @@ -152,33 +245,57 @@ export function mapChildrenIntoArray( /** - * Defines a way to serialize/deserialize a url tree. + * @whatItDoes Serializes and deserializes a URL string into a URL tree. + * + * @description The url serialization strategy is customizable. You can + * make all URLs case insensitive by providing a custom UrlSerializer. + * + * See {@link DefaultUrlSerializer} for an example of a URL serializer. * * @stable */ export abstract class UrlSerializer { /** - * Parse a url into a {@link UrlTree} + * Parse a url into a {@link UrlTree}. */ abstract parse(url: string): UrlTree; /** - * Converts a {@link UrlTree} into a url + * Converts a {@link UrlTree} into a url. */ abstract serialize(tree: UrlTree): string; } /** - * A default implementation of the serialization. + * @whatItDoes A default implementation of the {@link UrlSerializer}. + * + * @description + * + * Example URLs: + * + * ``` + * /inbox/33(popup:compose) + * /inbox/33;open=true/messages/44 + * ``` + * + * DefaultUrlSerializer uses parenthesis to serialize secondary segments (e.g., popup:compose), the + * colon syntax to specify the outlet, and the ';parameter=value' syntax (e.g., open=true) to + * specify route specific parameters. * * @stable */ export class DefaultUrlSerializer implements UrlSerializer { + /** + * Parse a url into a {@link UrlTree}. + */ parse(url: string): UrlTree { const p = new UrlParser(url); return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment()); } + /** + * Converts a {@link UrlTree} into a url. + */ serialize(tree: UrlTree): string { const segment = `/${serializeSegment(tree.root, true)}`; const query = serializeQueryParams(tree.queryParams);