26

I have defined some route data in my app routing module like below:

    const appRoutes:Routes = [
  {path: '', component: LoginComponent, data:[{PageName:"Login Page"}]}]

I want to get the data globally so that I can use appRoutes in app.component.ts to get the URL redirection related information as below:

export class AppComponent {
  title = 'Welcome';
  constructor(public router: Router, public authenticationService: AuthenticationService) {
    this.router.events.subscribe(event => {
        console.log("Url",event.urlAfterRedirects);
        console.log("Page Name", router[PageName]); //Not working
      }

I tried injecting ActivatedRoute but it's not getting updated after each redirection.

Is there anyway, where I can configure page name and get it in global app.component.ts.

danday74
  • 52,471
  • 49
  • 232
  • 283
user1188867
  • 3,726
  • 5
  • 43
  • 69

6 Answers6

31

Try to filter and loop your events instead of subscribe

constructor(router:Router, route:ActivatedRoute) {
    router.events
      .filter(e => e instanceof NavigationEnd)
      .forEach(e => {
        this.title = route.root.firstChild.snapshot.data['PageName'];
    });
}

Please check the following working demo: https://plnkr.co/edit/rBToHRaukDlrSKcLGavh?p=info

Hristo Eftimov
  • 13,845
  • 13
  • 50
  • 77
  • 2
    I added the above code to my app.component.ts . I am getting the value as undefined. – user1188867 Apr 20 '17 at 08:59
  • Can you create a plunker? It's hard to help you like that. As you see my working demo works, so we are very close to fix your issue :) – Hristo Eftimov Apr 20 '17 at 09:05
  • I apologise Its a big project with multiple modules i cant create plunker out of it. – user1188867 Apr 20 '17 at 09:53
  • 1
    ok, I understand :) Now I see a small difference between my example and your code. In the Routes array for the `data` property you are using an array: `data:[{PageName:"Login Page"}]` Can you try my example with an object: `data:{PageName:"Login Page"}`. Maybe for that, you receive `undefined`. – Hristo Eftimov Apr 20 '17 at 09:57
  • Thanks Eftimov, It worked :) I changed array to object and since i have multiple modules in project i have add some more code as below : var pageName = route.root.firstChild.snapshot.data['trackPageName']; if(!pageName) pageName = route.root.firstChild.snapshot.firstChild.data['trackPageName']; – user1188867 Apr 20 '17 at 10:39
  • I am glad to hear that :) – Hristo Eftimov Apr 21 '17 at 06:47
  • 1
    this is the updated answer for future angulars, https://stackoverflow.com/questions/60269666/angular-get-route-data-in-app-component –  Sep 14 '20 at 03:45
23

If you had statically routed using Router object like below:

{
  path: '',
  pathMatch: 'full',
  component: NameComponent,
  data: { variableName: 'variableValue' }
},

On ngOnInit() you can use ActivatedRoute object to recover the data you passed from Router definition:

ngOnInit() {
  this.localVariable = this.route.snapshot.data['variableName'];
}

Obs: I am using Angular 5!

codejockie
  • 9,020
  • 4
  • 40
  • 46
Pablo
  • 386
  • 2
  • 5
  • 2
    this.route is instance of what? – userx Apr 27 '18 at 13:44
  • 1
    can you post a stackblitz link? – userx Apr 27 '18 at 14:56
  • best answer by far! – tatsu Jun 12 '18 at 07:40
  • @FurqanShakir route is ActivatedRoute from @angular/router – Kerim092 Aug 18 '18 at 02:32
  • 5
    This approach works for components that are part of the route component being routed. This approach does *not* work from within the root app component itself. when `ngOnInit` is called on the root app component as requested, `snapshot.data` is an empty object. – Randolpho Jan 07 '19 at 20:41
  • @Randolpho That's true, it's because the snapshot is for the part of the route that belongs to the component. `AppComponent` is not typically passed as a route, that's why it doesn't have that property. As @pablo mentioned, this is only in the case where you defined the component in routing to have route data. If you do need this functionality from AppComponent, you're doing something globally and you'll need to drill through route data as shown in https://stackoverflow.com/a/50268145/227299 – Ruan Mendes Jun 19 '19 at 14:28
  • 1
    Works for me only when using *root.firstChild* like in `route.root.firstChild.snapshot.data['variableName']` – Wintermute Jul 24 '20 at 15:37
23

This code was written by Todd Motto (Google Developer Expert) to access route data in a parent component or app component. Works like a gem.

import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'
import { filter, map, mergeMap } from 'rxjs/operators'

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

ngOnInit() {
  this.router.events.pipe(
    filter(event => event instanceof NavigationEnd),
    map(() => this.route),
    map(route => {
      while (route.firstChild) route = route.firstChild
      return route
    }),
    filter(route => route.outlet === 'primary'),
    mergeMap(route => route.data)
  ).subscribe(data =>
    console.log('data', data)
  )
}

See: https://ultimatecourses.com/blog/dynamic-page-titles-angular-2-router-events

In his example he is using route data to set the page title in app component.

Why accessing route data in a parent is so complicated I'll never know!

danday74
  • 52,471
  • 49
  • 232
  • 283
  • 5
    This looks quite painful/depressing. Like, why is it this difficult? I could never have figured this out on my own ;( – George43g Dec 29 '19 at 04:21
  • Oh god, it actually works. This is the only one that works. I think it might be because to access the current route data in the primary outlet from a parent component that holds the outlet is a little more complicated, especially if you take into account the fact that there may be multiple routers. But it also makes me lose a bit of confidence in my own abilities. I guess I'll keep trying and keep learning... – George43g Dec 29 '19 at 04:26
4

For Angular 5+

This service retrieves data on the current route: (in my case "title")

import { Injectable } from "@angular/core";
import { Router, ActivatedRouteSnapshot } from "@angular/router";

@Injectable()
export class AppRoutingService {

  constructor(private router: Router) { }

  public getRouteTitle(): string {
    return this.getRouteData("title");
  }

  private getRouteData(data: string): any {
    const root = this.router.routerState.snapshot.root;
    return this.lastChild(root).data[0][data];
  }

  private lastChild(route: ActivatedRouteSnapshot): ActivatedRouteSnapshot {
    if (route.firstChild) {
      return this.lastChild(route.firstChild);
    } else {
      return route;
    }
  }
}

Component Logic:

import { Component, OnInit, OnDestroy } from "@angular/core";
import { Router, NavigationEnd } from "@angular/router";

// SERVICES
import { AppRoutingService } from "../../shared/services/app-routing.service";

@Component()
export class NavSubmenuComponent implements OnInit, OnDestroy {
  title: string = "";
  routerEvents: any;

  constructor(private router: Router, private appRoutingService: AppRoutingService ) { }

  ngOnInit() {
    this.title = this.appRoutingService.getRouteTitle();

    this.routerEvents = this.router.events
      .filter(event => event instanceof NavigationEnd)
      .subscribe(() => {
        this.title = this.appRoutingService.getRouteTitle();
      });
  }

  ngOnDestroy() {
    this.routerEvents.unsubscribe();
  }
}
neox5
  • 1,621
  • 13
  • 16
3

In my case this work for angular 8:

onActivate(outlet) in <router-outlet> will be called automatically every time when the route is activated.

in html

<router-outlet (activate)='onActivate(outlet)' #outlet="outlet"></router-outlet>

in component

onActivate(outlet: RouterOutlet) {
    outlet.activatedRoute.data.pipe(map(data => console.log('Router data', data))).toPromise().then();
  }

Dont forget import

import {RouterOutlet} from '@angular/router';
import {map} from 'rxjs/operators';
stackdruid
  • 33
  • 1
  • 3
0

If you are willing to wait until the ngAfterViewInit event you can link to the router outlet using viewchild.

i.e.

  @ViewChild('router')
  private routerOutlet: RouterOutlet;

  ngAfterViewInit() {
    this.routerOutlet.activateEvents
      .pipe(
        map(() => this.routerOutlet
          .activatedRouteData
        )
      )
    .subscribe((data) => {
        // Code 
    });
  }

<router-outlet #router="outlet"></router-outlet>