Angular 2:从父组件获取RouteParams

时间:2015-12-28 20:17:47

标签: angular angular2-routing

如何从父组件获取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');
  }

  ...
}

但是,如何在这些子组件中获得相同的'username'参数?做与上面相同的技巧,不会这样做。因为这些参数是在ProfileComponent中定义的还是什么?

@Component({
  ...
})

export class ChildOneComponent {

  public username: string;

  constructor(
    public params: RouteParams
  ) {
    this.username = params.get('username');
    // returns null
  }

  ...
}

13 个答案:

答案 0 :(得分:55)

<强>更新

现在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();
    }
}

<强> ORIGINAL:

以下是我使用“@ angular / router”:“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 }]
    }
];

答案 1 :(得分:9)

您不应该尝试在RouteParams中使用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']);
    })
  }


  ...
}

更新:从此拉取请求(角度测试版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: 从角度2.0.0.beta15开始的小变化:

现在currentInstruction不再是一个功能了。此外,您必须加载root路由器。 (感谢@ Lxrd-AJ报道)

@Component({
  ...
})

export class ChildOneComponent {

  public username: string;

  constructor(_router: Router) {
    let instruction = _router.root.currentInstruction;
    this.username = instruction.component.params['username'];
  }

  ...
}

答案 2 :(得分:7)

如GünterZöchbauer所述,我使用https://github.com/angular/angular/issues/6204#issuecomment-173273143的评论来解决我的问题。我使用Injector中的angular2/core类来获取父级的路由选择。原来角度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);
}

答案 3 :(得分:6)

我找到了一个丑陋但有效的解决方案,通过请求父母(正是第二个祖先)注射器,并从此处获取RouteParams

这样的东西
@Component({
  ...
})
export class ChildOneComponent {
  public username: string;

  constructor(injector: Injector) {
    let params = injector.parent.parent.get(RouteParams);

    this.username = params.get('username');
  }
}

答案 4 :(得分:4)

RC5 + @ angular / router&#34;:&#34; 3.0.0-rc.1解决方案:似乎已弃用this.router.routerState.queryParams。您可以通过这种方式获得父路线参数:

constructor(private activatedRoute: ActivatedRoute) {
}    

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

答案 5 :(得分:2)

您可以从注入器中获取子组件内部父路径的组件,然后从子组件获取任何组件。在你的情况下像这样

@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');
  }

  ...
}

答案 6 :(得分:2)

如果要为代码编写单元测试,将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();
    }
}

请注意,您应该使用&#34; providers&#34;将此类服务的范围扩展到您的父组件及其子组件。在父组件装饰器中。

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

答案 7 :(得分:2)

在RC6,路由器3.0.0-rc.2 (也可能在RC5中工作),你可以从URL中获取路由参数作为快照,以防params不会改变,没有观察到这一个班轮:

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

不要忘记按如下方式注入ActivatedRoute:

constructor(private route: ActivatedRoute) {};

答案 8 :(得分:2)

使用RxJS&#39; 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'];
        });
  }
}

答案 9 :(得分:1)

我最终为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.
 *
 * e.g.
 * {
 *   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];
  }

  ...
}  

答案 10 :(得分:0)

FINAL 中,在 RXJS 的帮助下,您可以合并两张地图(来自儿童和家长):

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

可能有的其他问题:

  • 上面使用是否真的是一个好主意 - 因为耦合(将子组件与父级的参数耦合 - 不在api级别 - 隐藏耦合),
  • 在RXJS方面是否是正确的方法(它需要硬核RXJS用户反馈;)

答案 11 :(得分:0)

您可以使用以下内容在快照上执行此操作,但如果更改,则不会更新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(); } } 属性。

此示例还说明了如何通过合并所有参数observable来订阅所有祖先参数更改并查找您感兴趣的参数。但是,请小心使用此方法,因为可能有多个祖先具有相同的参数键/名称。

{{1}}

答案 12 :(得分:0)

从Angular 8的父组件获取RouteParams-

我有一条路线http://localhost:4200/partner/student-profile/1234/info

父母路线-学生资料

Param -1234(student_id)

子路线-信息


访问子路径中的参数(信息)-

导入

import { ActivatedRoute, Router, ParamMap } from '@angular/router';

构造函数

constructor(private activatedRoute: ActivatedRoute, private router: Router) { }

访问父级路由参数

this.activatedRoute.parent.paramMap.subscribe((params: ParamMap) => this.studentId = (params.get('student_id')));


现在,我们的变量 studentId 具有参数值。