Angular 2 new Router: How to get router parameters of a child component?
The child parameters are associated/stored with the child ActivatedRoute. They are not available on the parent's ActivatedRoute. So you first need to get the child's ActivatedRoute using getter firstChild
or children
.
Then, the parent can either subscribe to child parameter changes:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
export class ParentComponent implements OnInit, OnDestroy {
private sub: Subscription;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.sub = this.route.firstChild.params.subscribe(
params => console.log(params.id));
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
or it can get a snapshot of the child parameters:
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
export class ParentComponent {
constructor(private route: ActivatedRoute) {}
someMethod() {
console.log(this.route.firstChild.snapshot.params.id);
}
}
If you want to get all of the children (e.g., if you have multiple outlets), use ActivatedRoute.children
or ActivatedRouteSnapshot.children
to get an array of child ActivatedRoutes or child ActivatedRouteShapshots.
It's super easy to get the child parameters via ActivatedRoute, however you can quickly run into issues if you change the current child.
First a couple notes:
activatedRoute.firstChild
property is anActivatedRoute
instance and NOT an observable.- Also note that
activatedRoute.paramMap
is an observable.
Here's how you can run into problems:
- Consider a component with two child routes - and corresponding components - where only one is shown at a time (for example a tabbed interface).
- If you access
firstChild.paramMap
inside yourngOnInit
handler you'll be able to subscribe to it and monitor the parameters as they change. This will look and work just fine. - If you switch to the second tab and then back to the first everything will break. This is because you originally subscribed
paramMap
on an ActivatedRoute instance that doesn't exist anymore. - Important: This is only a problem if you're trying to access the child's
paramMap
. If you're trying to access your 'own' paramMap, or the child component also injectsparamMap
then everything will be fine.
The cleanest solution to this I've found is as follows:
Note: First inject router: Router
in addition to route: ActivatedRoute
.
const firstChildParams$ = this.router.events.pipe(filter(e => e instanceof NavigationEnd),
startWith(undefined),
switchMap(e => this.route.firstChild!.paramMap));
What this does is listens for only NavigationEnd events, after which a new firstChild
will be available. By using switchMap
you don't need to worry about unsubscribing to old redundant maps. Also not that the actual value of the navigation event is never used, and startWith
is needed to be able to immediately handle parameters the first time.
I've been collecting helpful things like this into a RouterHelperService that I can inject anywhere, and not have to remember all this craziness.
Some day I may suggest that there should be an observable equivalent of firstChild
, then this wouldn't be a problem. However it would perhaps introduce even more confusion in other scenarios!
The ActivatedRoute
has getters to access its parent/child route information.
In order to access the first child route from the parent, you would use:
this.route.firstChild.params
If you wanted all the child routes you would use the children
property. This returns an array of ActivatedRoute
this.route.children
If you were in a child route and needed parameters from the parent:
this.route.parent.params