7

I need to modify the breadcrumb value in the data object of my current route. Here is my route configuration.

      {
    path: "users",
    component: UserListComponent,
    children: [
      {
        path: ":id",
        component: UserComponent,
        data: {
          breadcrumb: '<User name here>'
        },
       }
    ],
    data: {
      breadcrumb: 'Users'
    }
  },

I am trying to do this:

        this._route.data = { breadcrumb: this.user.displayName }; //_route is ActivatedRoute

but it doesn't work. Any help would be appreciated. Thanks.

Danish
  • 694
  • 1
  • 7
  • 15

3 Answers3

4

The data property of a route is static and cannot be modified after creation (source: https://angular.io/api/router/Data).

There are probably many other ways to accomplish your goal. The most common method would be to grab the :id param from the route (I'm assuming this is the user id) and feed it into a UserService (which you create) that then returns the user's displayName.

A more advanced option:

While it might be overkill for your particular use case, in my app I created a breadcrumb building component which extracts static breadcrumb components from the route's data properties and renders them. For example, one of my route configs looks like:

...
import { OrganizationBreadcrumbComponent } from './organization-breadcrumb.component'
import { OrganizationMenuComponent } from './organization-menu.component'
import { ProfileBreadcrumbComponent } from './profile/profile-breadcrumb.component'
import { PeopleBreadcrumbComponent } from './people/people-breadcrumb.component'

const routes: Routes = [
  {
    path: 'organization/:organizationId',
    data: {
      breadcrumb: OrganizationBreadcrumbComponent,
      menu: OrganizationMenuComponent,
    },
    canActivate: [OrganizationGuard],
    children: [
      {
        path: 'profile',
        data: {
          breadcrumb: ProfileBreadcrumbComponent,
        },
        component: ProfileComponent,
      },
      {
        path: 'people',
        data: {
          breadcrumb: PeopleBreadcrumbComponent,
        },
        component: PeopleComponent,
      }
    ],
  },
];
...

In my app, I add component classes (i.e. ProfileBreadcrumbComponent) to the data objects in my route config. I then have a breadcrumb rendering component which subscribes to the router's data param, extracts these breadcrumb component classes, and dynamically builds the breadcrumb trail using them. Each individual breadcrumb component can do whatever it needs to do to build its own view.

For example, you could create a UserDisplayNameBreadcrumbComponent which, in ngOnInit(), grabs the current user id from the route params, looks up that user, finds their display name, and renders it.

I actually posted a question about this a while ago (before I got everything working) that explains more, if you are interested: https://stackoverflow.com/a/43715200/5490505

I use ngrx/router-store in my app which makes subscribing to all the breadcrumbs for a given route pretty easy.

John
  • 9,249
  • 5
  • 44
  • 76
0

I assume you want to modify the data before the navigation starts. Because it is not clear from the question.

Look for NavigationStart event and set this._route.snapshot.data instead of this._route.data.

this.router.events
.filter(event => event instanceof NavigationStart)
.subscribe(() => {
     this._route.snapshot.data = { breadcrumb: this.user.displayName };
});
Amit Chigadani
  • 28,482
  • 13
  • 80
  • 98
0

I had a similar problem and followed the advice here: https://github.com/angular/angular/issues/13860#issuecomment-271884682

Basically, the idea is that you don't define the children of the router immediately, but delay that. So, in your Routes above, just set children: [] and take that data and put it in another Routes object in the UserListComponent. Then, in that component you have something like the following for your constructor:

constructor(activatedRoute: ActivatedRoute) {
    activatedRoute.routeConfig.children = routes;
}

So, putting it all together, two files are involved and we end up with:

// user-routing.module.ts
const routes = [
  {
    path: "users",
    component: UserListComponent,
    children: [],
    data: {
      breadcrumb: 'Users'
    }
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class UserRoutingModule {
  constructor() { }
}

and

// user.component.ts
const routes = [
  {
    path: ":id",
    component: UserComponent,
    data: {
      breadcrumb: '<User name here>'
    },
  }
];
@Component({
  selector: 'app-user',
  templateUrl: './user.component.html'
})
export class UserComponent {
  constructor(activatedRoute: ActivatedRoute) {
    routes[0].data.breadcrumb = 'Bob Johnson';
    activatedRoute.routeConfig.children = routes;
  }
}

This allows you to pass what appears to be dynamic, or late-bound, data to the router since you have an instantiated class with dependencies injected with which you can do any manipulation you want on the data before attaching it to the router.

cjbarth
  • 4,189
  • 6
  • 43
  • 62