developer tip

Angular 2 : 부모 구성 요소에서 RouteParams 가져 오기

copycodes 2020. 11. 5. 08:14
반응형

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

당신은 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']);
    })
  }


  ...
}

업데이트 : 이 풀 리퀘스트 (angular beta.9) : https://github.com/angular/angular/pull/7163

이제 .NET없이 현재 명령어에 액세스 할 수 있습니다 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 : angular 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'];
  }

  ...
}

Günter Zöchbauer가 언급했듯이 https://github.com/angular/angular/issues/6204#issuecomment-173273143 의 주석을 사용하여 문제를 해결했습니다. Injector클래스를 사용하여 angular2/core부모의 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);
}

나는 부모 (정확히 두 번째 조상) 인젝터를 요청하고 여기에서 가져옴으로써 추악하지만 작동하는 해결책을 찾았 RouteParams습니다.

같은 것

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

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

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

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

인젝터에서 자식 구성 요소 내부의 부모 경로 구성 요소를 가져온 다음 자식 구성 요소에서 가져올 수 있습니다. 이런 경우

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

  ...
}

코드에 대한 단위 테스트를 작성하려는 경우 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


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

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

  ...
}  

RXJS의 도움이 거의없는 FINAL 에서는 두 맵을 결합 할 수 있습니다 (하위 및 상위에서) :

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

다른 질문이있을 수 있습니다.

  • 위에서 사용하는 것이 정말 좋은 생각입니까-커플 링 (부모의 매개 변수와 자식 구성 요소를 결합하기 때문에-API 수준이 아닌-숨겨진 커플 링),
  • Is it proper approach in term of RXJS (it would require hardcore RXJS user feedback ;)

You can do it on the snapshot with the following, but if it changes, your id property will not be updated.

This example also shows how you can subscribe to all ancestor parameter changes and look for the one you are interested in by merging all of the parameter observables. However, be careful with this method because there could be multiple ancestors that have the same parameter key/name.

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

참고URL : https://stackoverflow.com/questions/34500147/angular-2-getting-routeparams-from-parent-component

반응형