A breadcrumb component for @ngrx/router

@ngrx/router is, at the moment, one of the best choices for a router component in Angular 2, and Vladivostok, the third iteration of Angular 2’s official router, will take a very heavy inspiration from it. At the moment we are using it to handle our routes, and the need arose to create a breadcrumb component for certain parts of the application.

You can see a working example here.

@ngrx/router‘s API is very light and sparse, but not necessarily incomplete – a lot of the actual implementation is assumed to be left in the hands of the user. This is powered by the use of Observables for Route, RouteParams, QueryParams, etc. A great example of this assumption is the fact that instead of a set of interfaces like CanReuse/CanActivate/CanDeactivate, the router only ever activates components when they change after a route change – any changes in parameters are handled manually by default. More work, but also a clearer image of what one can and cannot do with the tool, and a lot more control.

The first thing we found was that routes have a property – options – that serves the express purpose of holding custom data. A simple usage is this:

export const routes: Route[] = [
    path: '/',
    component: Home,
    options: {
        breadcrumb: 'Home Sweet Home'
    children: [
        path: '/component-a',
        component: ComponentA,
        options: {
            breadcrumb: 'A Component'
        children: [
            path: '/one',
            component: One,
            options: {
                breadcrumb: 'The One'

And the breadcrumb component is as such:

    selector: 'breadcrumbs',
    directives: [ NgFor ],
        <span *ngFor="let breadcrumb of breadcrumbs; let isLast = last">
            <a [linkTo]="breadcrumb.path">{{breadcrumb.name}}</a>
            <span *ngIf="!isLast"> &gt; </span>
export class Breadcrumbs {
    private breadcrumbs: any[];

    constructor(private routerInstruction: RouterInstruction) {
                match => {
                    this.breadcrumbs = this.getBreadcrumbs(match);

    private getBreadcrumbs (match: Match) {
        let breadcrumbs = [];
        let path = '';

        for (let i = 0; i < match.routes.length; i++) {
            path = path[path.length - 1] === '/' ? path.substr(0, path.length - 1) : path;
            path += match.routes[i].path ? this.makePath(match.routes[i], match) : '';
            if ((match.routes[i].options || {}).breadcrumb) {
                    name: match.routes[i].options.breadcrumb,
                    path: path

        return breadcrumbs;

    private makePath (route: Route, match: Match) {
        return pathToRegexp.compile(route.path)(match.routeParams);

RouterInstruction is one Observable that gives us all the information we need. By watching it, a Match object containing the array of matched routes is returned. All that was left was to create the urls, as @ngrx/router uses only url strings (as opposed to the array notation you’ll find in @angular/router, for instance) – but as @ngrx/router uses path-to-regexp to parse urls, to it was only a matter of using it to compile from the parsed data, and get the urls.

All in all, a very simple solution. Omitted are the use of translations and using asynchronously loaded data (like a profile name) in the breadcrumb – the former is trivial and very unrelated, and the latter we are using stores for, and it’s perhaps a good topic for another post.


1 Comment

  1. This is really helpful, thanks. It looks like only half of the ngRx Router stuff is documented. The source code is actually relatively short. But, as I am new to RxJS in general, it can be a bit hard to follow. I was trying to understand how the RouterInstruction fit into it and what the “match” was actually doing.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s