How to set dynamic page titles in Angular 2/4
I’ve been creating projects using Google’s Angular frameworks for over 3 years now and in that time, I’ve needed to change the document title as the user moved through the app.
In Angular 1.x, I surmounted this challenge by moving my ng-app
declaration to html
tag (instead of the body
tag) and then controlled the page title by using $broadcast
and $on
to determine when to change the $rootScope
property that I used to keep track of the page title.
Angular 2/4 has been a different beast entirely and I never gave it (setting dynamic page titles) much thought until I worked on a project that required it. I was fine with having a single page title (usually the application’s name) for the lifetime of the apps I’ve built.
I did a bit of googling and found an article by Todd Moto of the Angular Team that solved the problem in the cleanest way I’ve seen yet.
As I usually do, I’m writing this up here so I don’t go head-scratching at a later date when I need to do this again.
import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
constructor(
private titleService: Title,
private activatedRoute: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
this.router.events
.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) => this.titleService.setTitle(event['title']));
}
}
Here’s a link to the Github Gist.
For explanations, please refer to the original post from Todd Moto.