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'])
}
  1. For every events from router, I filter only NavigationEnd event
  2. Then I map this event to the activatedRoute (because I want to read the value of activatedRoute on NavigationEnd).
  3. I map the activatedRoute to the firstChild (first children declared with RouterModule.forRoot()).
  4. Then a switchMap is made to get the data of this route, a switchMap because data is an observable.
  5. 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