Parent components gets empty Params from Activated

2020-02-03 06:15发布

问题:

I have a main component that has a router-outlet in it. In the component that is loaded in the router-outlet I grab the url parameter like this:

ngOnInit(): void {
    // _route is injected ActivatedRoute
    this._route.params.subscribe((params: Params) => {
        if(params['url']){
          this.testUrl = params['url'].replace(new RegExp('\%2[fF]', 'g'), '/');

        }

    });
}

This works fine, but when I try it on my top level component the params object is always empty. I don't understand why as the nested components param object has the data in it and I am trying to access it exactly the same way. There are no errors to go on, the param object is just empty.

Why doesn't my parent component get the right Params object from ActivatedRoute?

edit:

as requested full parent component

import { OnInit, Component, Directive } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
})
export class AppComponent {
  public testUrl: string;
  constructor(private router: Router, private _route: ActivatedRoute) {

  }
  ngOnInit(): void{
    this._route.queryParams.subscribe((params: Params) => {
      console.log(params);

      if (params['url']) {
        this.testUrl = params['url'].replace(new RegExp('\%2[fF]', 'g'), '/');
        alert(params['url']);
      }
    });
  }

}

router code for app.module.ts:

RouterModule.forRoot([
  { path: '', component: CheckMobileComponent },
  { path: '**', component: CheckMobileComponent }
]),

router code for nested module:

RouterModule.forChild([
 { path: 'report', component: MobileReportComponent }

There is no directly specified route for my app.component as it is loaded by a selector in index.html.

回答1:

ActivatedRoute: Contains the information about a route associated with a component loaded in an router outlet. If you would like to access route details outside of it, use the code below.

import { Component } from '@angular/core';
import { Router, ActivatedRoute, Params, RoutesRecognized } from '@angular/router';

export class AppComponent {

    constructor(private route: ActivatedRoute, private router: Router) {

    }

    ngOnInit(): void {
        this.router.events.subscribe(val => {

            if (val instanceof RoutesRecognized) {

                console.log(val.state.root.firstChild.params);

            }
        });

    }
}

There are other ways to share data in between components for example by using a service.

For more details about how you can tackle this as concept, read comments here.



回答2:

The Very simple answer

    import { Component } from '@angular/core';
    import { Router, ActivatedRoute, Params, RoutesRecognized } from 
   '@angular/router';

    export class AppComponent {

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

   ngOnInit(): void {
     this.actRoute.firstChild.params.subscribe(
       (params: any) => {
         if (params.hasOwnProperty('<whatever the param name>') != '') {
            //do whatever you want
            console.log(params.<whatever the param name>);
          } 
       }
    });

   }
}


回答3:

ActivatedRoute works for components loaded via router-outlet. From docs - it:

Contains the information about a route associated with a component loaded in an outlet.

I don't think you can use it in components that are not loaded in an outlet. It also doesn't work in base classes your component extends.

class A { constructor(public route: ActivatedRoute) } 
class B extends A { ngOnInit() { this.route; } }        // not working
class C { constructor(public route: ActivatedRoute) }   // working if loaded in outlet


回答4:

I was having a very similar problem with this mainly due to my misunderstanding of how routes actually worked. I thought I could just go up the chain of path parameters and each one would be a parent/child relationship. However, if a route has more than one element to the path, (e.g. /dashboard and profile/:user_id) it will depend on how you set up the routes in your routing module(s).

To explain a different way that made it click for me:

// If I am trying to access ActivatedRoute from the CheckMobileComponent (say 
// through a `router-outlet`), I could get it through something like 
// `this._route.firstChild`

{ path: '', component: CheckMobileComponent, children: [

    // If I want to get things from the '' context in MobileReportComponent, it 
    // would be through something like `this._route.parent`

    { path: 'report', component: MobileReportComponent }

  ]   

}


回答5:

If you'd like to access the router parameters via a service, this approach will not work! consider using a service to prevent the replication of the "Route params value extraction logic" (from this Medium article):

@Injectable({
  providedIn: 'root'
})
export class MyParamsAwareService {
  constructor(private router: Router) { 
    this.router.events
      .pipe(
        filter(e => (e instanceof ActivationEnd) && (Object.keys(e.snapshot.params).length > 0)),
        map(e => e instanceof ActivationEnd ? e.snapshot.params : {})
      )
      .subscribe(params => {
      console.log(params);
      // Do whatever you want here!!!!
      });
  }
}