Angularで動的にページのタイトルを変更

# はじめに

SPA の Web アプリケーションを開発していく中で、ページごとにタイトルを変更したいと思ったことはないでしょうか？  
Angular の標準機能でタイトルを変更することができますが、一部実装を加える事によってページごとにタイトルを設定することができるようになります。  
タイトルの変更方法について、2つほど紹介させていただきます。

# デモ

タイトルを変更を組み込んだアプリケーションのデモを見ていただきます。  
以下のタイミングでタイトルを変更できることが確認できます。

1. 「Go To title1」、「Go To title2」で画面遷移時
2. 「ChangeTitle」、「RestoreTitle」のボタン押下時

![title-change-demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180065/ae2ee9c7-b4bf-a663-40f6-1346c9b36496.gif)


# 実装

## ① 任意の値でタイトルを変更

Angular に標準で用意されている [`@angular/platform-browser Title`](https://angular.io/api/platform-browser/Title) の `setTitle()` を実行することでタイトルを変更できます。  
デモでは input にバインドした値を `setTitle()` の引数として設定し、ボタン押下のタイミングでタイトルを更新しています。

- HTML

  ```html
  <div class="row no-gutters m-3 w-25">
    <input
      id="titleInput"
      name="titleInput"
      type="text"
      class="form-control"
      placeholder="Please input title"
      [(ngModel)]="title"
    />
  </div>

  <div class="row no-gutters m-3">
    <button class="btn btn-primary" (click)="changeTitle()">
      Change title
    </button>
    <button class="btn btn-danger ml-3" (click)="restoreTitle()">
      Restore title
    </button>
  </div>
  ```

- Typescript

  ```typescript
  import { Component } from "@angular/core";
  import { Title } from "@angular/platform-browser";

  @Component({
    selector: "app-home",
    templateUrl: "./home.component.html",
    styleUrls: ["./home.component.scss"],
  })
  export class HomeComponent {
    public title = "AngularTitleChange";

    constructor(private titleService: Title) {}

    public changeTitle() {
      this.titleService.setTitle(this.title);
    }

    public restoreTitle() {
      this.title = "AngularTitleChange";
      this.changeTitle();
    }
  }
  ```

## ② ページ遷移時に自動的にタイトルを変更

app.component.ts にて NavigationEnd のイベントをサブスクライブし、画面遷移時に `setTitle()` を実行することでタイトルを変更します。  
各ページのタイトルは、app-routing.module.ts にて `data: { title: 'Title1' }` の様にタイトルについての付加情報を追加することで反映されます。

- app.component.ts

  ```typescript
  import { Component, OnInit } from "@angular/core";
  import { Title } from "@angular/platform-browser";
  import { ActivatedRoute, NavigationEnd, Router } from "@angular/router";
  import { filter, map } from "rxjs/operators";

  @Component({
    selector: "app-root",
    templateUrl: "./app.component.html",
    styleUrls: ["./app.component.scss"],
  })
  export class AppComponent implements OnInit {
    constructor(
      private titleService: Title,
      private router: Router,
      private activatedRoute: ActivatedRoute
    ) {}

    ngOnInit() {
      const appTitle = this.titleService.getTitle();
      this.router.events
        .pipe(
          filter((event) => event instanceof NavigationEnd),
          map(() => {
            const child = this.activatedRoute.firstChild;
            if (child.snapshot.data.title) {
              return child.snapshot.data.title;
            }
            return appTitle;
          })
        )
        .subscribe((ttl: string) => {
          this.titleService.setTitle(ttl);
        });
    }
  }
  ```

- app-routing.module.ts

  ```typescript
  const routes: Routes = [
    {
      path: "",
      component: HomeComponent,
    },
    {
      path: "title1",
      component: Title1Component,
      data: { title: "Title1" },
    },
    {
      path: "title2",
      component: Title2Component,
      data: { title: "Title2" },
    },
  ];
  ```

# 参考

https://blog.bitsrc.io/dynamic-page-titles-in-angular-98ce20b5c334