Angular Dynamic Page Titles with Nested Routes

September 30, 2021

This is a quick demo of one way you can accomplish dynamic page titles in the html head tags with Angular. This should work in most recent versions of Angular (8+) but let me know on Twitter if it doesn’t work or if there are better solutions to this problem. I found it semi-frustrating compared to how easy it is in Vue and React land. This crazy map and filter stuff is needed for nested route structures.

You can define a base title for your application in index.html.

<!-- index.html -->

<title>My Fancy Application</title>
// app.component.ts

@Component({
  selector: 'app-root',
  template: '<router-outlet></router-outlet>',
})
export class AppComponent implements OnInit {
  constructor(
    private titleService: Title,
    private activatedRoute: ActivatedRoute,
    private router: Router,
  ) {
ngOnInit() {
    // Grab the title from index.html
    const appTitle = this.titleService.getTitle();

    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((event) => {
        if (event.title) {
          return this.titleService.setTitle(`${appTitle} | ${event.title}`);
        }
        // This is neccessary to unset the more specific title if it was the previous page.
        return this.titleService.setTitle(appTitle);
      });
  }
  }
// routes.ts

{
    path: '',
    component: WrapperComponent,
    canActivate: [AuthGuard],
    children: [
      {
        path: 'blog',
        component: BlogComponent,
        data: { title: 'Blog' },
      },
      {
        path: 'docs',
        children: [
          {
            path: '',
            component: DocsComponent,
            data: { title: 'Docs' },
          },
          {
            path: 'examples',
            component: ExamplesComponent,
            children: [
              {
                path: '',
                component: ExamplesListingComponent,
                data: { title: 'Examples' },
              },
              {
                path: ':id',
                component: ExampleDetailsComponent,
                data: { title: 'Examples | Example Details' },
              },
            ],
          },

        ],
      },
    ],
  },

Written by Matt Gregg, a UI engineer who lives and works in Minneapolis, MN

Have something to say about this post? Tweet at me

matt@codegregg.com