Angular 2:从父组件获取RouteParams


79

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

  ...
}

孩子的输入属性如何?例如,在父模板中:<child-one-component [username]="username"> ...
Mark Rajcok 2015年

那还会起作用<routerlink [username]="username">...吗?那是@MarkRajcok可以走的路吗?
Aico Klein Ovink 2015年

我想您是在问类似的事情是否<a [router-link]="[ './....', {username: username} ]会起作用。抱歉,我不知道这是否行得通。(我还没有玩太多的路由。)
Mark Rajcok 2015年

对不起@MarkRajcok,我打错了..我的意思是<router-outlet></router-outlet>,我应该在上面输入一些内容。因为孩子的路由西港岛线呈现有..
AICO克莱恩Ovink

Answers:


72

更新:

现在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 / 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 }]
    }
];

2
您需要在ngOnInit中调用它(如图所示),而不是在构造函数中调用它,因为我一开始就很愚蠢地尝试这样做。
卡梅伦

2
自Angular 5.2起,还有另一种方法不需要您遍历parent1次以上。请参阅stackoverflow.com/a/48511516/4185989,不过仍然值得考虑此答案中的subscribe/unsubscribe模式。
jmq

在Angular 6中this.activatedRoute.parent.snapshot.params.someParam
Tasnim Reza

@jmq指出的解决方案也是角度6的最佳解决方案,我们不需要单独订阅父ID。
学习...

完美的解决方案!购买为什么我需要订阅才能获得父级参数?参数已经在那里!:: thinking
:::

10

您不应该尝试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']);
    })
  }


  ...
}

更新:从这个拉取请求(角度beta.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'];
  }

  ...
}

这是应该为子路线完成的方式吗?我也遇到了这个问题,子路由无法看到父组件的routeparams。例如,路由/ users /:user_id / posts /:post_id,我无法从posts组件中获取user_id...。我似乎不得不使用RouteRegistry。
mharris7190 '16

@ mharris7190我更新了答案。从angular beta.9开始,您可以直接从Router组件获取当前指令。
ProGM

感谢更新。我即将从beta.6升级到beta.13,因此我会在以后尝试。
mharris7190 '16

3
对此答案稍作修改,请使用_router.root.currentInstruction.component.params['id']。重点是root,因为您现在从root路由器而不是从current路由器获取currentInstruction _router。PS:我正在使用angular2.0.0-beta.15
Lxrd-AJ

_router.root不再存在。(我使用Angular 2.4.7)
EivindGussiåsLøkseth'17

7

正如GünterZöchbauer所提到的,我在https://github.com/angular/angular/issues/6204#issuecomment-173273143中使用了注释来解决我的问题。我使用Injector类fromangular2/core来获取父类的routeparams。事实证明,角度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);
}

8
在angular2 RC路由器上这不再起作用。
Inn0vative16年

6

我找到了一个丑陋但可行的解决方案,方法是请求父级(确切地说是第二个祖先)注射器,并RouteParams从此处获取。

就像是

@Component({
  ...
})
export class ChildOneComponent {
  public username: string;

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

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

非常感谢您分享此信息,Angular团队是否有任何Bugtracker条目或声明,说明将来如何处理?
Marcus Riemer

似乎.parent已在RC3上删除
theFreedomBanana

4

RC5 + @ angular / router“:” 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);
  });

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

  ...
}

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

请注意,您应该使用父组件装饰器中的“提供者”将此类服务的作用域限定到父组件及其子组件。

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


2

在RC6中,路由器3.0.0-rc.2(也可能在RC5中起作用)中,您可以从URL中获取路由参数作为快照,以防参数不变,而使用此衬板则无法观察到:

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

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

constructor(private route: ActivatedRoute) {};


2

使用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'];
        });
  }
}

1

我最终为Angular 2 rc.1编写了这种hack

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];
  }

  ...
}  

很棒!我最终将此方法私有化为MergedRouteParams实现get标准RouteParams类方法的类的内部(第二个参数为index,默认为零)。
Jim Buck

0

FINAL中,几乎不需要RXJS的帮助,您就可以将两个地图(来自孩子和父母的地图)组合在一起:

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

一个人可能有其他问题:

  • 在上面使用它真的是一个好主意-因为耦合(将子组件与父级的参数耦合-不在api级别-隐藏的耦合),
  • 就RXJS而言,这是否合适?(这需要RXJS的核心用户反馈;)

0

您可以使用以下方法在快照上进行操作,但是如果更改,则您的 id则不会更新属性。

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

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

0

从Angular 8的父组件获取RouteParams-

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

家长路线-学生资料

参数-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具有param值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.