Angular 2: getting RouteParams from parent component

前端 未结 13 860
暖寄归人
暖寄归人 2020-11-28 04:47

How do I get the RouteParams from a parent component?

App.ts:

@Component({
  ...
})

@RouteConfig([
  {path: \'/\', component: HomeCompo         


        
相关标签:
13条回答
  • 2020-11-28 05:01

    UPDATE:

    Now that Angular2 final was officially released, the correct way to do this is the following:

    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:

    Here is how i did it using the "@angular/router": "3.0.0-alpha.6" package:

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

    In this example the route has the following format: /parent/:id/child/:childid

    export const routes: RouterConfig = [
        {
            path: '/parent/:id',
            component: ParentComponent,
            children: [
                { path: '/child/:childid', component: ChildComponent }]
        }
    ];
    
    0 讨论(0)
  • 2020-11-28 05:01

    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();
      }
    }
    
    0 讨论(0)
  • 2020-11-28 05:03

    Passing Injector instance to constructor in child component may not be good if you want to write unit tests for your code.

    The easiest way to work around this is to have a service class in the parent component, in which you save your required params.

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

    Then you just inject the same service to child components and access the params.

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

    Note that you should scope such service to your parent component and its child components using "providers" in parent component decorator.

    I recommend this article about DI and scopes in Angular 2: http://blog.thoughtram.io/angular/2015/08/20/host-and-visibility-in-angular-2-dependency-injection.html

    0 讨论(0)
  • 2020-11-28 05:08

    Getting RouteParams from parent component in Angular 8 -

    I have a route http://localhost:4200/partner/student-profile/1234/info

    Parent route - student-profile

    Param - 1234 (student_id)

    Child route - info


    Accessing param in child route (info) -

    Import

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

    Constructor

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

    Accessing parent route params

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


    Now, our variable studentId has the param value.

    0 讨论(0)
  • I ended up writing this kind of hack for 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;
    }
    

    Now in view I collect parameters in view instead of reading RouteParams I just get them through router:

    @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];
      }
    
      ...
    }  
    
    0 讨论(0)
  • 2020-11-28 05:11

    You shouldn't try to use RouteParams in your ChildOneComponent.

    Use RouteRegistry, instead!

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

    UPDATE: As from this pull request (angular beta.9): https://github.com/angular/angular/pull/7163

    You can now access to the current instruction without recognize(location.path(), []).

    Example:

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

    I haven't tried it, yet

    Further details here:

    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

    UPDATE 2: A small change as from angular 2.0.0.beta15:

    Now currentInstruction is not a function anymore. Moreover, you have to load the root router. (thanks to @Lxrd-AJ for reporting)

    @Component({
      ...
    })
    
    export class ChildOneComponent {
    
      public username: string;
    
      constructor(_router: Router) {
        let instruction = _router.root.currentInstruction;
        this.username = instruction.component.params['username'];
      }
    
      ...
    }
    
    0 讨论(0)
提交回复
热议问题