Angular 2: nhận RouteParams từ thành phần chính


79

Làm cách nào để lấy RouteParams từ một thành phần chính?

App.ts:

@Component({
  ...
})

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

export class HomeComponent {
  ...
}

Và sau đó, trong ParentComponent, tôi có thể dễ dàng lấy thông số tên người dùng của mình và đặt các tuyến con.

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

  ...
}

Nhưng sau đó, làm thế nào tôi có thể lấy cùng một tham số 'tên người dùng' này trong các thành phần con đó? Làm thủ thuật tương tự như trên, không làm điều đó. Vì những thông số đó được xác định tại ProfileComponent hay gì đó ??

@Component({
  ...
})

export class ChildOneComponent {

  public username: string;

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

  ...
}

Làm thế nào về một tài sản đầu vào trên trẻ em? Ví dụ: trong mẫu mẹ:<child-one-component [username]="username"> ...
Mark Rajcok

Điều đó cũng sẽ hoạt động <routerlink [username]="username">...? Và đó có phải là cách để đi sau @MarkRajcok không?
Aico Klein Ovink

Tôi nghĩ bạn đang hỏi liệu một cái gì đó giống như <a [router-link]="[ './....', {username: username} ]sẽ hoạt động. Xin lỗi, tôi không biết liệu điều đó có hiệu quả hay không. (Tôi chưa chơi với định tuyến nhiều.)
Mark Rajcok

Tôi xin lỗi @MarkRajcok, tôi đã gõ sai .. Ý tôi là <router-outlet></router-outlet>, tôi có nên nhập thông tin vào đó không. Bởi vì các tuyến đường con wil làm cho có ..
AICO Klein Ovink

Câu trả lời:


72

CẬP NHẬT:

Bây giờ Angular2 cuối cùng đã chính thức được phát hành, cách chính xác để làm điều này là như sau:

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

NGUYÊN:

Đây là cách tôi đã thực hiện bằng cách sử dụng gói "@ angle / 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();
    }
}

Trong ví dụ này, tuyến đường có định dạng sau: / parent /: id / child /: childid

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

2
Bạn cần gọi điều này trong ngOnInit (như được hiển thị) chứ không phải trong hàm tạo như tôi đã cố gắng làm lúc đầu.
Cameron

2
Có một cách thay thế kể từ Angular 5.2 mà không yêu cầu bạn xem qua hơn parent1 lần. Xem stackoverflow.com/a/48511516/4185989 Tuy nhiên, vẫn đáng xem xét mẫu subscribe/ unsubscribetừ câu trả lời này.
jmq 13/02/18

Trong góc 6this.activatedRoute.parent.snapshot.params.someParam
Tasnim Reza

Giải pháp được chỉ ra bởi @jmq cũng là giải pháp tốt nhất cho góc 6, chúng tôi không cần đăng ký riêng cho id cha.
learning ...

Giải pháp hoàn hảo! Mua tại sao tôi cần đăng ký để nhận được các thông số chính? Thông số đã ở đó rồi! ::
Thinking

10

Bạn không nên cố gắng sử dụng RouteParamstrong của bạn ChildOneComponent.

Sử dụng RouteRegistry, thay thế!

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


  ...
}

CẬP NHẬT: Như từ yêu cầu kéo này (phiên bản beta.9 góc): https://github.com/angular/angular/pull/7163

Bây giờ bạn có thể truy cập vào hướng dẫn hiện tại mà không cần recognize(location.path(), []).

Thí dụ:

@Component({
  ...
})

export class ChildOneComponent {

  public username: string;

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

  ...
}

Tôi vẫn chưa thử

Thông tin chi tiết tại đây:

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

CẬP NHẬT 2: Một thay đổi nhỏ so với góc 2.0.0.beta15:

Bây giờ currentInstructionkhông phải là một chức năng nữa. Hơn nữa, bạn phải tải rootbộ định tuyến. (cảm ơn @ Lxrd-AJ đã báo cáo)

@Component({
  ...
})

export class ChildOneComponent {

  public username: string;

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

  ...
}

Đây có phải là cách nó được cho là được thực hiện cho các tuyến đường con? Tôi cũng đang gặp phải vấn đề này trong đó các tuyến con không thể nhìn thấy các routeparams của các thành phần mẹ. Ví dụ: route / users /: user_id / posts /: post_id, tôi không thể lấy user_id từ thành phần posts .... Tôi thấy có vẻ khó khi phải sử dụng RouteRegistry.
mharris7190

@ mharris7190 Tôi đã cập nhật câu trả lời của mình. Bắt đầu từ phiên bản beta.9 góc, bạn có thể lấy hướng dẫn hiện tại trực tiếp từ thành phần Bộ định tuyến.
ProGM

Cảm ơn các cập nhật. Tôi sắp nâng cấp từ beta.6 lên beta.13 nên tôi sẽ dùng thử sau khi hoàn thành.
mharris7190

3
Một chút chỉnh sửa cho câu trả lời này, Sử dụng _router.root.currentInstruction.component.params['id']. Nhấn mạnh vào root vì bây giờ bạn nhận được currentInstruction từ bộ định tuyến gốc chứ không phải _router. Tái angular2.0.0-beta.15
bút

_router.root không tồn tại nữa. (Tôi sử dụng Angular 2.4.7)
Eivind Gussiås Løkseth

7

Như đã đề cập bởi Günter Zöchbauer, tôi đã sử dụng nhận xét tại https://github.com/angular/angular/issues/6204#issuecomment-173273143 để giải quyết vấn đề của mình. Tôi đã sử dụng Injectorlớp from angular2/coređể tìm nạp các routeparams của cha mẹ. Hóa ra góc 2 không xử lý các tuyến đường lồng nhau sâu. Có thể họ sẽ thêm điều đó trong tương lai.

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
Điều này không hoạt động nữa trên bộ định tuyến RC góc 2.
Inn0vative1

6

Tôi đã tìm thấy một giải pháp xấu nhưng hiệu quả, bằng cách yêu cầu bộ phun cha mẹ (chính xác là tổ tiên thứ 2) và bằng cách lấy RouteParamstừ đây.

Cái gì đó như

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

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

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

Cảm ơn rất nhiều vì đã chia sẻ điều này, có mục nhập hoặc tuyên bố nào của nhóm góc cạnh về cách xử lý vấn đề này trong tương lai không?
Marcus Riemer

Dường .parent đó đã được gỡ bỏ trên RC3
theFreedomBanana

4

RC5 + @ angle / router ":" 3.0.0-rc.1 GIẢI PHÁP: Có vẻ như nó this.router.routerState.queryParamsđã không được dùng nữa. Bạn có thể lấy các thông số tuyến mẹ theo cách này:

constructor(private activatedRoute: ActivatedRoute) {
}    

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

2

Bạn có thể lấy thành phần của tuyến mẹ bên trong thành phần con từ bộ tiêm và sau đó lấy bất kỳ thành phần nào từ thành phần con. Trong trường hợp của bạn như thế này

@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

Truyền cá thể Injector cho hàm tạo trong thành phần con có thể không tốt nếu bạn muốn viết các bài kiểm tra đơn vị cho mã của mình.

Cách dễ nhất để giải quyết vấn đề này là có một lớp dịch vụ trong thành phần mẹ, trong đó bạn lưu các tham số cần thiết của mình.

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

Sau đó, bạn chỉ cần đưa cùng một dịch vụ vào các thành phần con và truy cập các tham số.

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

Lưu ý rằng bạn nên phạm vi dịch vụ đó cho thành phần mẹ và các thành phần con của nó bằng cách sử dụng "nhà cung cấp" trong trình trang trí thành phần mẹ.

Tôi giới thiệu bài viết này về DI và phạm vi trong Angular 2: http://blog.thoughtram.io/angular/2015/08/20/host-and-visibility-in-angular-2-dependency-injection.html


2

Trong RC6, bộ định tuyến 3.0.0-rc.2 (có thể cũng hoạt động trong RC5), bạn có thể lấy các thông số định tuyến từ URL dưới dạng ảnh chụp nhanh trong trường hợp các thông số đó không thay đổi mà không có các thông số quan sát với lớp lót này:

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

Đừng quên tiêm ActivatedRoute như sau:

constructor(private route: ActivatedRoute) {};


2

Với RxJS's Observable.combineLatest, chúng ta có thể hiểu được điều gì đó gần với việc xử lý các tham số thành ngữ:

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

Tôi đã viết loại hack này cho 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;
}

Bây giờ trong chế độ xem, tôi thu thập các thông số trong chế độ xem thay vì đọc, RouteParamstôi chỉ lấy chúng thông qua bộ định tuyến:

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

  ...
}  

Hoạt động tuyệt vời! Tôi đã kết thúc việc đặt phương thức này ở chế độ riêng tư bên trong một MergedRouteParamslớp triển khai getphương thức của RouteParamslớp chuẩn (tham số thứ hai là chỉ mục, mặc định là 0).
Jim Buck

0

Trong CUỐI CÙNG với sự trợ giúp nhỏ của RXJS, bạn có thể kết hợp cả hai bản đồ (từ con và mẹ):

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

Một số câu hỏi khác có thể có:

  • Có thực sự là một ý tưởng hay khi sử dụng ở trên - vì ghép nối (cặp thành phần con với tham số của cha mẹ - không ở cấp api - ghép nối ẩn),
  • Đó có phải là cách tiếp cận đúng đắn về RXJS không (nó sẽ yêu cầu phản hồi của người dùng RXJS khó tính;)

0

Bạn có thể làm điều đó trên ảnh chụp nhanh với những điều sau đây, nhưng nếu nó thay đổi, thuộc tính của bạn idsẽ không được cập nhật.

Ví dụ này cũng cho thấy cách bạn có thể đăng ký tất cả các thay đổi tham số tổ tiên và tìm kiếm thay đổi mà bạn quan tâm bằng cách hợp nhất tất cả các tham số có thể quan sát. Tuy nhiên, hãy cẩn thận với phương pháp này vì có thể có nhiều tổ tiên có cùng khóa / tên tham số.

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

Lấy RouteParams từ thành phần mẹ trong Angular 8 -

Tôi có một tuyến đường http: // localhost: 4200 / partner / student-profile / 1234 / info

Tuyến đường chính - hồ sơ sinh viên

Thông số - 1234 (student_id)

Tuyến đường trẻ em - thông tin


Truy cập thông số trong tuyến trẻ em (thông tin) -

Nhập khẩu

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

Constructor

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

Truy cập thông số tuyến đường chính

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


Bây giờ, biến studentId của chúng ta có giá trị tham số.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.