6

I have the following routes configured in app-routing.module.ts

const routes: Routes = [
  {
    path: 'abc/:id', component: AbcComponent, data: { category: 'Public' }
  },
  {
    path: 'xyz/:id/tester/:mapId', component: XyzComponent, data: { category: 'Private' }
  },
  { path: '**', redirectTo: '/page-not-found', pathMatch: 'full'}
]

In app.component.ts I would like to get the category of each Route based on the URL passed:

Ex: going to http://myapp.com/abc/123 should return category as Public going to http://myapp.com/xyz/123/tester/456 should return category as Private

Here is what I have so far:

constructor(
    private activatedRoute: ActivatedRoute,
    private router: Router
)
{
  checkRouteAndGetCategory()
}

checkRouteAndGetCategory()
{
  this.router.events.pipe(
        filter(event => event instanceof NavigationEnd),
        map(() => this.activatedRoute),
        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)
      )
}

The above code does not seem to get the right route. Ex: If I am on http://myapp.com/abc/123 page and navigated to http://myapp.com/xyz/123/tester/456, it seems to get the data for http://myapp.com/abc/123 page.

0

3 Answers 3

13

This is what I have in my app component

constructor(private route: ActivatedRoute) {
}

ngOnInit(): void {
  this.router.events.pipe(
    filter(event => event instanceof NavigationEnd),
    map(() => this.rootRoute(this.route)),
    filter((route: ActivatedRoute) => route.outlet === 'primary'),
    mergeMap((route: ActivatedRoute) => route.data)
  ).subscribe((event: {[name: string]: any}) => {
    this.titleService.setRouteTitle(event['title']);
  });
}

private rootRoute(route: ActivatedRoute): ActivatedRoute {
  while (route.firstChild) {
    route = route.firstChild;
  }
  return route;
}

Where my app routes look like:

{ path: 'login', component: LoginComponent, data: { title: 'Login' } }

And my title service is responsible for setting the title.

The only difference I see between mine and yours is that you bind to the router in your constructor and I do it in ngOnInit. Can you try calling what you have in ngOnInit? I'm not sure if this will make a difference, but it's worth a shot.

Sign up to request clarification or add additional context in comments.

2 Comments

We did have different names for our injected ActivatedRoute. I also think that both of our methods do the same thing - they were just being called in different places. If yours still doesn't work from ngOnInit, then I have no idea what's going on. Next step would be to recreate in a stackblitz.
I posted the bounty, I think this answer is great, looking if there is more simple code, lot of people have different answers, stackoverflow.com/questions/43512695/… this.title = route.root.firstChild.snapshot.data['PageName']; etc
1

I would consider moving this to a service, say CategoryService

CategoryService

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

@Injectable({
  providedIn: 'root'
})
export class CategoryService {
  constructor(private router: Router ) { }
  private routerEvents =  this.router.events;
  private navigationEndEvent = this.routerEvents
    .pipe(filter(event => event instanceof NavigationEnd))
  category$ = this.navigationEndEvent
    .pipe(
      mergeMap(() => this.rootRoute(this.router.routerState.root).data),
      map(({category}: any) => category)
    )
  private rootRoute = (route: ActivatedRoute): ActivatedRoute => {
    return route.firstChild ? this.rootRoute(route.firstChild) : route;
  }
}

Component

constructor(private categoryService: CategoryService) {
  }
  category$ = this.categoryService.category$;
  ...
}

HTML

<span>{{ category$ | async }}</span>

Sample on Stackblitz

1 Comment

mergeMap(() => this.rootRoute(this.router.routerState.root).data) is what made it for me, instread of mergeMap(() => this.rootRoute(this.route).data).
-1

It's a short way to get route data in the component.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.