Angular 2:从父组件获取RouteParams

如何从父组件获取RouteParams?

App.ts

 @Component({ ... }) @RouteConfig([ {path: '/', component: HomeComponent, as: 'Home'}, {path: '/:username/...', component: ParentComponent, as: 'Parent'} ]) export class HomeComponent { ... } 

然后,在ParentComponent ,我可以很容易地获得我的用户名参数并设置子路由。

Parent.ts

 @Component({ ... }) @RouteConfig([ { path: '/child-1', component: ChildOneComponent, as: 'ChildOne' }, { path: '/child-2', component: ChildTwoComponent, as: 'ChildTwo' } ]) export class ParentComponent { public username: string; constructor( public params: RouteParams ) { this.username = params.get('username'); } ... } 

但是,那么如何才能在这些子组件中获得相同的“用户名”参数呢? 做同样的技巧,如上所述,不这样做。 因为这些参数是在ProfileComponent中定义的?

 @Component({ ... }) export class ChildOneComponent { public username: string; constructor( public params: RouteParams ) { this.username = params.get('username'); // returns null } ... } 

更新:

现在Angular2 final已经正式发布了,正确的做法如下:

 export class ChildComponent { private sub: any; private parentRouteId: number; constructor(private route: ActivatedRoute) { } ngOnInit() { this.sub = this.route.parent.params.subscribe(params => { this.parentRouteId = +params["id"]; }); } ngOnDestroy() { this.sub.unsubscribe(); } } 

原版的:

这里是我如何使用“@angular/路由器”:“3.0.0-alpha.6”包:

 export class ChildComponent { private sub: any; private parentRouteId: number; constructor( private router: Router, private route: ActivatedRoute) { } ngOnInit() { this.sub = this.router.routerState.parent(this.route).params.subscribe(params => { this.parentRouteId = +params["id"]; }); } ngOnDestroy() { this.sub.unsubscribe(); } } 

在这个例子中,路由具有以下格式:/ parent /:id / child /:childid

 export const routes: RouterConfig = [ { path: '/parent/:id', component: ParentComponent, children: [ { path: '/child/:childid', component: ChildComponent }] } ]; 

您不应该尝试在您的ChildOneComponent使用ChildOneComponent

改用RouteRegistry

 @Component({ ... }) export class ChildOneComponent { public username: string; constructor(registry: RouteRegistry, location: Location) { route_registry.recognize(location.path(), []).then((instruction) => { console.log(instruction.component.params['username']); }) } ... } 

更新:从这个拉请求(angularβ.9): https : //github.com/angular/angular/pull/7163

你现在可以不用recognize(location.path(), [])来访问当前的指令。

例:

 @Component({ ... }) export class ChildOneComponent { public username: string; constructor(_router: Router) { let instruction = _router.currentInstruction(); this.username = instruction.component.params['username']; } ... } 

我还没有尝试过

更多细节在这里:

https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta9-2016-03-09 https://angular.io/docs/ts/latest/api/router/Router-class html的

更新2:从angular2.0.0.beta15一个小的变化:

现在currentInstruction不再是一个function。 而且,你必须加载root路由器。 (感谢@ Lxrd-AJ的报告)

 @Component({ ... }) export class ChildOneComponent { public username: string; constructor(_router: Router) { let instruction = _router.root.currentInstruction; this.username = instruction.component.params['username']; } ... } 

正如GünterZöchbauer所提到的,我使用了https://github.com/angular/angular/issues/6204#issuecomment-173273143上的评论来解决我的问题。; 我使用angular2/coreInjector类来获取父级的Routeparams。 原来的angular度2不处理深层嵌套的路线。 也许他们会在未来增加这个。

 constructor(private _issueService: IssueService, private _injector: Injector) {} getIssues() { let id = this._injector.parent.parent.get(RouteParams).get('id'); this._issueService.getIssues(id).then(issues => this.issues = issues); } 

我find了一个丑陋的工作解决scheme,通过请求父(正是第二个祖先)注入器,并从这里获取RouteParams

就像是

 @Component({ ... }) export class ChildOneComponent { public username: string; constructor(injector: Injector) { let params = injector.parent.parent.get(RouteParams); this.username = params.get('username'); } } 

你可以从注射器中取出子组件内部的父路由,然后从子组件获取任何东西。 在你这种情况下

 @Component({ ... }) export class ChildOneComponent { public username: string; constructor( public params: RouteParams private _injector: Injector ) { var parentComponent = this._injector.get(ParentComponent) this.username = parentComponent.username; //or this.username = parentComponent.params.get('username'); } ... } 

如果要为代码编写unit testing,将Injector实例传递给子组件中的构造函数可能不太好。

解决这个问题的最简单方法是在父组件中有一个服务类,在其中保存所需的参数。

 @Component({ template: `<div><router-outlet></router-outlet></div>`, directives: [RouterOutlet], providers: [SomeServiceClass] }) @RouteConfig([ {path: "/", name: "IssueList", component: IssueListComponent, useAsDefault: true} ]) class IssueMountComponent { constructor(routeParams: RouteParams, someService: SomeServiceClass) { someService.id = routeParams.get('id'); } } 

然后,您只需将相同的服务注入到子组件并访问参数。

 @Component({ template: `some template here` }) class IssueListComponent implements OnInit { issues: Issue[]; constructor(private someService: SomeServiceClass) {} getIssues() { let id = this.someService.id; // do your magic here } ngOnInit() { this.getIssues(); } } 

请注意,您应该使用父组件装饰器中的“提供者”将这种服务范围扩展到父组件及其子组件。

我推荐这篇关于DI和范围在Angular 2中的文章: http : //blog.thoughtram.io/angular/2015/08/20/host-and-visibility-in-angular-2-dependency-injection.html

RC5 + @ angular / router“:”3.0.0-rc.1解决scheme:似乎this.router.routerState.queryParams已被弃用。 你可以这样获得父路由参数:

 constructor(private activatedRoute: ActivatedRoute) { } this.activatedRoute.parent.params.subscribe( (param: any) => { let userId = param['userId']; console.log(userId); }); 

我最终为Angular 2 rc.1写了这种黑客攻击

 import { Router } from '@angular/router-deprecated'; import * as _ from 'lodash'; interface ParameterObject { [key: string]: any[]; }; /** * Traverse route.parent links until root router and check each level * currentInstruction and group parameters to single object. * * eg * { * id: [314, 593], * otherParam: [9] * } */ export default function mergeRouteParams(router: Router): ParameterObject { let mergedParameters: ParameterObject = {}; while (router) { let currentInstruction = router.currentInstruction; if (currentInstruction) { let currentParams = currentInstruction.component.params; _.each(currentParams, (value, key) => { let valuesForKey = mergedParameters[key] || []; valuesForKey.unshift(value); mergedParameters[key] = valuesForKey; }); } router = router.parent; } return mergedParameters; } 

现在我在视图中收集参数,而不是阅读RouteParams我只是通过路由器获取它们:

 @Component({ ... }) export class ChildishComponent { constructor(router: Router) { let allParams = mergeRouteParams(router); let parentRouteId = allParams['id'][0]; let childRouteId = allParams['id'][1]; let otherRandomParam = allParams.otherRandomParam[0]; } ... } 

在RC6中,路由器3.0.0-rc.2 (也可能在RC5中工作),如果参数不会改变,则可以从URL中获取路由参数作为快照,

this.route.snapshot.parent.params['username'];

不要忘记注入ActivatedRoute如下:

constructor(private route: ActivatedRoute) {};

用RxJS的Observable.combineLatest ,我们可以得到一些接近于惯用的参数处理:

 import 'rxjs/add/operator/combineLatest'; import {Component} from '@angular/core'; import {ActivatedRoute, Params} from '@angular/router'; import {Observable} from 'rxjs/Observable'; @Component({ /* ... */ }) export class SomeChildComponent { email: string; id: string; constructor(private route: ActivatedRoute) {} ngOnInit() { Observable.combineLatest(this.route.params, this.route.parent.params) .forEach((params: Params[]) => { this.id = params[0]['id']; this.email = params[1]['email']; }); } } 

最后几乎没有RXJS的帮助下,你可以结合两个地图(从孩子和父母):

 (route) => Observable .zip(route.params, route.parent.params) .map(data => Object.assign({}, data[0], data[1])) 

其他问题可能有:

  • 是否真的是一个好主意 – 因为耦合(夫妇孩子组件与父母的参数 – 不是在api水平 – 隐藏的耦合),
  • 在RXJS方面是否合适?(这将需要核心RXJS用户反馈;)

你可以在下面的快照上做,但如果它改变了,你的id属性将不会被更新。

这个例子还展示了如何订阅所有的祖先参数变化,并通过合并所有参数observables来寻找你感兴趣的variables。 但是,要小心这种方法,因为可能有多个具有相同参数键/名称的祖先。

 import { Component } from '@angular/core'; import { ActivatedRoute, Params, ActivatedRouteSnapshot } from '@angular/router'; import { Observable } from 'rxjs/Observable'; import { Subscription } from 'rxjs/Subscription'; import 'rxjs/add/observable/merge'; // This traverses the route, following ancestors, looking for the parameter. function getParam(route: ActivatedRouteSnapshot, key: string): any { if (route != null) { let param = route.params[key]; if (param === undefined) { return getParam(route.parent, key); } else { return param; } } else { return undefined; } } @Component({ /* ... */ }) export class SomeChildComponent { id: string; private _parameterSubscription: Subscription; constructor(private route: ActivatedRoute) { } ngOnInit() { // There is no need to do this if you subscribe to parameter changes like below. this.id = getParam(this.route.snapshot, 'id'); let paramObservables: Observable<Params>[] = this.route.pathFromRoot.map(route => route.params); this._parametersSubscription = Observable.merge(...paramObservables).subscribe((params: Params) => { if ('id' in params) { // If there are ancestor routes that have used // the same parameter name, they will conflict! this.id = params['id']; } }); } ngOnDestroy() { this._parameterSubscription.unsubscribe(); } }