How to get data from Route or ActivatedRoute when subscribing to router.events.subscribe in Angular2?
Something like this:
constructor(private router: Router,
private activatedRoute: ActivatedRoute)
{
this.router.events
.filter(event => event instanceof NavigationEnd)
.map(() => this.activatedRoute)
.map(route => route.firstChild)
.switchMap(route => route.data)
.map(data => data['asdf'])
}
- For every events from router, I filter only NavigationEnd event
- Then I map this event to the activatedRoute (because I want to read the value of activatedRoute on NavigationEnd).
- I map the activatedRoute to the firstChild (first children declared with RouterModule.forRoot()).
- Then a switchMap is made to get the data of this route, a switchMap because data is an observable.
- Finally I map the data object to the key I want, in this case asdf
The following is updated to work with rxjs v6
constructor(private router: Router,
private activatedRoute: ActivatedRoute)
{
this.router.events
.pipe(
filter(event => event instanceof NavigationEnd),
map(() => this.activatedRoute),
map(route => route.firstChild),
switchMap(route => route.data),
map(data => data['asdf']))
}
Here is a modified example using @Neelavar link example.
It might look long but it's simple, be patient, if you stick through it, it should work. Just following the steps outlined should take a few minutes.
Full Explanation for my setup, for beginners
You should already know how to create components and setup routing, I won't explain that in depth.
1. Setup Data Property in Routes Array
In your routes array (you will find this either in app.module.ts or app-routes.module.ts or in some cases a routes.ts file).
If you can't find this, check basic routing setup in:
- angular docs
- a video as well
a basic setup is all you need!
Add the data property like so (you will need to generate the home component):
export const routes: Routes = [
{ path: 'home', component: HomeComponent, data: {title: 'home'} },
{ path: '', pathMatch: 'full', redirectTo: '/home' },
];
2. Create a class
RouteData.ts, I have it in the same folder space as app.module.ts
export class RouteData {
title: string;
}
This is just to add types for using the observable in typescript, the IDE can then autocomplete "title" or "id" or "animation" for me if I add that to the data class later.
3. Import the following into app.component.ts
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { filter, map, switchMap } from 'rxjs/operators';
import { RouteData } from './route-data';
Then above the constructor code, declare the variable
routeData$: Observable<RouteData>;
Then inside the constructor
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
) {}
4. Then inside constructor again
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
) {
this.routeData$ = router.events.pipe(
filter(routeEvent => routeEvent instanceof NavigationEnd),
map(() => activatedRoute),
map(activatedRoute => activatedRoute.firstChild),
switchMap(firstChild => firstChild.data),
map((data: RouteData) => data)
);
}
Explanation of code adapted from @Tuizi link Example Comment:
For every event from router, filter only for the NavigationEnd event (when the router has completed navigation).
Then map (return) the currently activatedRoute.
Map the activatedRoute to the firstChild (The first child of this route in the router state tree).
Then a switchMap emits the data of this route, use a switchMap because each "data" that is emitted is an observable, the switch map will cancel the old observable when a new one is emitted, saving memory.
Map (return) the data object, assign it a type of RouteData.
Finally you can use this Observable in a template using async pipe
<span *ngIf="routeData$ | async as routeData">
{{ routeData.title | titlecase }}
</span>
*A note: "async as" breaks type checking in the template at the moment :(
github issue