feat(router): introduce ParamMap
to access parameters
The Router use the type `Params` for all of: - position parameters, - matrix parameters, - query parameters. `Params` is defined as follow `type Params = {[key: string]: any}` Because parameters can either have single or multiple values, the type should actually be `type Params = {[key: string]: string | string[]}`. The client code often assumes that parameters have single values, as in the following exemple: ``` class MyComponent { sessionId: Observable<string>; constructor(private route: ActivatedRoute) {} ngOnInit() { this.sessionId = this.route .queryParams .map(params => params['session_id'] || 'None'); } } ``` The problem here is that `params['session_id']` could be `string` or `string[]` but the error is not caught at build time because of the `any` type. Fixing the type as describe above would break the build because `sessionId` would becomes an `Observable<string | string[]>`. However the client code knows if it expects a single or multiple values. By using the new `ParamMap` interface the user code can decide when it needs a single value (calling `ParamMap.get(): string`) or multiple values (calling `ParamMap.getAll(): string[]`). The above exemple should be rewritten as: ``` class MyComponent { sessionId: Observable<string>; constructor(private route: ActivatedRoute) {} ngOnInit() { this.sessionId = this.route .queryParamMap .map(paramMap => paramMap.get('session_id') || 'None'); } } ``` Added APIs: - `interface ParamMap`, - `ActivatedRoute.paramMap: ParamMap`, - `ActivatedRoute.queryParamMap: ParamMap`, - `ActivatedRouteSnapshot.paramMap: ParamMap`, - `ActivatedRouteSnapshot.queryParamMap: ParamMap`, - `UrlSegment.parameterMap: ParamMap`
This commit is contained in:
@ -9,13 +9,15 @@
|
||||
import {Type} from '@angular/core';
|
||||
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import {map} from 'rxjs/operator/map';
|
||||
|
||||
import {Data, ResolveData, Route} from './config';
|
||||
import {PRIMARY_OUTLET, Params} from './shared';
|
||||
import {PRIMARY_OUTLET, ParamMap, Params, convertToParamMap} from './shared';
|
||||
import {UrlSegment, UrlSegmentGroup, UrlTree, equalSegments} from './url_tree';
|
||||
import {merge, shallowEqual, shallowEqualArrays} from './utils/collection';
|
||||
import {Tree, TreeNode} from './utils/tree';
|
||||
|
||||
|
||||
/**
|
||||
* @whatItDoes Represents the state of the router.
|
||||
*
|
||||
@ -110,6 +112,10 @@ export class ActivatedRoute {
|
||||
_futureSnapshot: ActivatedRouteSnapshot;
|
||||
/** @internal */
|
||||
_routerState: RouterState;
|
||||
/** @internal */
|
||||
_paramMap: Observable<ParamMap>;
|
||||
/** @internal */
|
||||
_queryParamMap: Observable<ParamMap>;
|
||||
|
||||
/** @internal */
|
||||
constructor(
|
||||
@ -149,6 +155,21 @@ export class ActivatedRoute {
|
||||
/** The path from the root of the router state tree to this route */
|
||||
get pathFromRoot(): ActivatedRoute[] { return this._routerState.pathFromRoot(this); }
|
||||
|
||||
get paramMap(): Observable<ParamMap> {
|
||||
if (!this._paramMap) {
|
||||
this._paramMap = map.call(this.params, (p: Params): ParamMap => convertToParamMap(p));
|
||||
}
|
||||
return this._paramMap;
|
||||
}
|
||||
|
||||
get queryParamMap(): Observable<ParamMap> {
|
||||
if (!this._queryParamMap) {
|
||||
this._queryParamMap =
|
||||
map.call(this.queryParams, (p: Params): ParamMap => convertToParamMap(p));
|
||||
}
|
||||
return this._queryParamMap;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`;
|
||||
}
|
||||
@ -225,6 +246,10 @@ export class ActivatedRouteSnapshot {
|
||||
_resolvedData: Data;
|
||||
/** @internal */
|
||||
_routerState: RouterStateSnapshot;
|
||||
/** @internal */
|
||||
_paramMap: ParamMap;
|
||||
/** @internal */
|
||||
_queryParamMap: ParamMap;
|
||||
|
||||
/** @internal */
|
||||
constructor(
|
||||
@ -267,6 +292,20 @@ export class ActivatedRouteSnapshot {
|
||||
/** The path from the root of the router state tree to this route */
|
||||
get pathFromRoot(): ActivatedRouteSnapshot[] { return this._routerState.pathFromRoot(this); }
|
||||
|
||||
get paramMap(): ParamMap {
|
||||
if (!this._paramMap) {
|
||||
this._paramMap = convertToParamMap(this.params);
|
||||
}
|
||||
return this._paramMap;
|
||||
}
|
||||
|
||||
get queryParamMap(): ParamMap {
|
||||
if (!this._queryParamMap) {
|
||||
this._queryParamMap = convertToParamMap(this.queryParams);
|
||||
}
|
||||
return this._queryParamMap;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
const url = this.url.map(segment => segment.toString()).join('/');
|
||||
const matched = this._routeConfig ? this._routeConfig.path : '';
|
||||
|
Reference in New Issue
Block a user