22

I am using angular2 router.

To draw the breadcrumb of an url, lets say site.com/a/b/c/15 I do the following:

  1. Get the route of site.com/a/b/c/15 and get the pretty name associated to the route
  2. Get the route of site.com/a/b/c and get the pretty name associated to the route
  3. Get the route of site.com/a/b and get the pretty name associated to the route
  4. Get the route of site.com/a and get the pretty name associated to the route

So lets say I do have the following routes:

{ path: 'a', component: A, data:{prettyName: 'I am A'}}
{ path: 'b', component: B, data:{prettyName: 'I am B'}},
{ path: 'c', component: C, data:{prettyName: 'I am C'}},

The result of my process would be an array containing {"I am C", "I am B", "I am C"} and thanks to that I can display a nice breadcrumb "I am A > I am B > I am C" that explains the current route.

This use to work with the router-deprecated doing

this.router.recognize(url).then((instruction) => {
    instruction.component.routeData.get('prettyName') // Would return 'I am ..'

However now; with the last router I am not able to process this recognize logic anymore.

How to get the route data associated to an url ?

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
ATX
  • 1,139
  • 2
  • 11
  • 29

3 Answers3

24

Updated for RC5

Instead of starting with the current URL and trying to get the routes from the URL, you can get all of the activated routes (associated with the primary outlet) from the RouterState:

After the end of each successful navigation lifecycle, the router builds a tree of ActivatedRoutes, which make up the current state of the router. We can access the current RouterState from anywhere in our application using the Router service and the routerState property.

The router state provides us with methods to traverse up and down the route tree from any activated route to get information we may need from parent, child and sibling routes. -- reference

Subscribe to router events, then, after each NavigationEnd event, walk down the tree of ActivatedRoutes from the root:

import { Component } from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import 'rxjs/add/operator/filter';

@Component({
  selector: 'breadcrumbs',
  template: `
  <div>
    breadcrumbs: 
    <span *ngFor="let breadcrumb of breadcrumbs; let last = last">
      <a [routerLink]="breadcrumb.url">{{breadcrumb.label}}</a>
      <span *ngIf="!last">></span>
    </span>
  </div>`
})
export class BreadcrumbsComponent {
  breadcrumbs: Array<Object>;
  constructor(private router:Router, private route:ActivatedRoute) {}
  ngOnInit() {
    this.router.events
      .filter(event => event instanceof NavigationEnd)
      .subscribe(event => {  // note, we don't use event
        this.breadcrumbs = [];
        let currentRoute = this.route.root,
            url = '';
        do {
          let childrenRoutes = currentRoute.children;
          currentRoute = null;
          childrenRoutes.forEach(route => {
            if(route.outlet === 'primary') {
              let routeSnapshot = route.snapshot;
              console.log('snapshot:', routeSnapshot)
              url += '/' + routeSnapshot.url.map(segment => segment.path).join('/');
              this.breadcrumbs.push({ 
                label: route.snapshot.data.breadcrumb,
                url:   url });
              currentRoute = route;
            }
          })
        } while(currentRoute);
      })
  }
}

Routes look like this:

{ path: '', component: HomeComponent, data: {breadcrumb: 'home'}}

Plunker - RC.5, router 3.0.0-rc.1


See also https://stackoverflow.com/a/38310404/215945 for a similar solution.

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 5
    I built a more polished version of this, check it out: https://github.com/alalonde/ng2-breadcrumbs – alalonde Aug 15 '16 at 18:17
  • I cannot help but think this is pretty ugly solution for something as simple as breadcrumbs. – hendrix Aug 16 '16 at 10:25
  • 1
    @hendrix, it is complicated/ugly because, as alalonde mentions in his github repo, "your navigation hierarchy may not directly match the slashes in your URL". – Mark Rajcok Aug 16 '16 at 17:29
  • do you have mistake?maybe there should be `if(route.outlet === PRIMARY_OUTLET)` instead of `...=== 'primary'` . suggested by @hendrix – T.Todua Aug 24 '16 at 12:05
  • @tazotodua yup. The string value `primary` probably changed since this answer was written. – hendrix Aug 24 '16 at 12:07
  • @tazotodua, `PRIMARY_OUTLET` was renamed `primary` -- see [Router changelog](https://github.com/angular/angular/blob/master/modules/@angular/router/CHANGELOG.md) for 3.0.0-rc.1. – Mark Rajcok Aug 24 '16 at 15:44
  • Amazing. Was plowing the web for this for 2 days to no avail. Well done Mark. Though the last is missing the label (separator is in place), and ng if for the regular `a` tag. Otherwise, it works like a charm (also with children). It's a shame the Angular official does not explain how to do this. – Amir Tugi Oct 04 '16 at 13:44
  • @MarkRajcok I tried to implement this but I'm getting error "Property 'breadcrumb' does not exist on type '{ [name: string]: any; }'." at line- label: route.snapshot.data.breadcrumb... Any help? – Protagonist Feb 08 '17 at 09:13
2

So far, the most feasable solution is (done):

  • Make the routes export/importable
  • Get the current url update from router.events subscribe
  • On url change, loop on the routes's path, see if the pattern match the url
  • If the patter match the url, get the data from the matching route

Pros: works

Cons: redoing url-route recognition manuall without using the ng2 router one

ATX
  • 1,139
  • 2
  • 11
  • 29
0

Any breadcrumb solution has to handle -

  1. declarative approach of defining breadcrumbs in Application routing.
  2. dynamic asynchronous way to update any route with a label from the server response.
  3. way to skip specific routes from displaying in breadcrumbs.

I have created an Angular library to handle all these, called xng-breadcrumbs - https://github.com/udayvunnam/xng-breadcrumb

feel free to check, An Angular app developed showing the breadcrumbs usage - https://xng-breadcrumb.netlify.com

Angular library planning, creation, and continuous release is well documented in this medium article

Uday Vunnam
  • 337
  • 2
  • 5