I wanted to set the page title in my angular app, so that every page would display its title in the tab. When I googled for solutions (i.e Dynamic Page Titles), they all involved more code than I needed. The offered solutions were great for apps with routes that had multiple nested children routes. However, the app I was working on had no children routes. Thus, I decided to come up with a simpler solution.

In Angular, you can add properties to a route by assigning an object to ‘data’. I assigned a title to each route using this method. Here is an example of what the routes should look like:

app-routing.module.ts

{path: ’emperor-penguin’, component: EmperorPenguinComponent, data: {title: ‘Emperor Penguin’}},
{path: ‘chinstrap-penguin’, component: ChinstrapPenguinComponent, data: {title: ‘Chinstrap Penguin’}},
{path: ‘royal-penguin’, component: RoyalPenguinComponent, data: {title: ‘Royal Penguin’}};

I then decided to put the code in the app.component.ts, since this component will be called upon on every page. In the constructor, you will need to inject Angular’s Router and Title services.

constructor(private route: Router, private titleService: Title) { }

The Router gives you access to the title of the page, while the Title service gives you the ability to set the title. I then created a new method called setTitle() which I called in ngOnInit().

ngOnInit(): void {
  this.setTitle();
}

setTitle(): void {
this.route.events.subscribe(event => {
 if (event instanceof NavigationEnd) {
   let title: string = this.route.routerState.snapshot.root.firstChild.data['title'];
   this.titleService.setTitle(title);
  }
 });
}

The setTitle()function subscribes to the events from the route. Since there’re so many different events, it is important to include the conditional specifying to only examine events that are the type of NavigationEnd, which gives you the details about the path of the route. Then, I was able to grab the title from this event and set the title. But what happens if you have a route that has children like this:

path: 'penguins', data: {title: 'Penguins'}, children: [
 {path: 'emperor-penguin', component: EmperorPenguinComponent, 
  data: {title: 'Emperor Penguin'}},
 {path: 'chinstrap-penguin', component: ChinstrapPenguinComponent, 
  data: {title: 'Chinstrap Penguin'}}
 ]
 });
}

The penguins path has two children – emperor penguin and chinstrap penguin. Our current code setup would not be able to grab the titles from these paths. In order to see the children path, we will need to add a conditional in the setTitle() function like so:

setTitle(): void {
 this.route.events.subscribe(event => {
   if (event instanceof NavigationEnd) {
     let title: string;
     if (this.isChildRoute()) {
       title = 
        this.route.routerState.snapshot.root.firstChild.firstChild.data['title'];
       this.titleService.setTitle(title);
     } else {
       title = this.route.routerState.snapshot.root.firstChild.data['title'];
       this.titleService.setTitle(title);
     }
   }
 });
}

isChildRoute(): ActivatedRouteSnapshot {
 return this.route.routerState.snapshot.root.firstChild.firstChild;
}

I added a new conditional that checks if it isChildRoute(). This if block sets the title for paths like Emperor Penguin and Chinstrap Penguin, while the else statement sets the title for parent paths like Penguins. If you examine the code closely, you’ll notice that when grabbing the title, we have one .firstChild. To grab the children titles, we have to look at the .firstChild.firstChild.

Conclusion

This solution works if you’re dealing with an app that has routes with either no children paths or only goes one level deep. If you’re doing something a bit more complicated than that, then I would recommend implementing more dynamic solutions. The lesson I learned from this experiment is that when you find an answer online, you should try to understand its intent and how it is solving your problem. If it’s solving your issue in a way that does not make sense for your situation, then you should consider finding a different solution, adapting the code to your needs, or coming up with your own solution and writing a blog post.=)

Share This