Angular: metaタグの埋め込み方法（ルーターを使う場合）

#Angular: metaタグの埋め込み方法（ルーターを使う場合）

[Angular: SEO対策基本](https://qiita.com/atomyah/items/951c026ffc27ebaa829a)でSEO対策に最低限するべきことをまとめておいた。今回はどーやってmetaタグを埋め込むか。普通に検索すると[Angularでコンポーネントからページの「メタ情報」を操作するには？](https://www.atmarkit.co.jp/ait/articles/1803/30/news135.html)のようにコンポーネントから直接`meta.addTag`なり`meta.updateTag`で操作するみたいだが、ムムム…。思った通りにクローラーが拾ってくれない。

bootstrap componentからルーターのイベント経由でメタタグ操作をする方が良いみたい。

###環境
```
Angular CLI: 7.1.4
Node: 10.15.3
OS: win32 x64
Angular: 7.1.4

"@angular/material": "^7.3.4"
```

###やり方
まずapp.route.tsファイルにメタ情報を追記していく。

```typescript
//app.route.ts
…略…
export const AppRoutes: Routes = [
    {path: "", component: HomeComponent,
    data: {
        title: 'hogehoge ー ホーム',
        description: 'hogeとはなんたらかんたら…',
        keywords: 'hoge,boyoyon,ororon',
        twittercard: 'summary',
        twittersite: '@hogehoge',
        twitterimage: 'https://hoge.io/hoge.img',
        url: 'https://hoge.io',
    }},
    {path: "introduction", component: IntroductionComponent,
    data: {
        title: 'hogehoge 紹介',
        description: 'hogeについてご紹介し…',
        keywords: 'hoge,boyoyon,ororon',
        twittercard: 'summary',
        twittersite: '@hogehoge',
        twitterimage: 'https://hoge.io/hoge_introduction.img',
        url: 'https://hoge.io/introduction',
    }},
…略…
```

次に、app.component.ts (もしくは独自のブートストラップコンポーネントにて)にて以下の通りに。

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

constructor(public router: Router, private route: ActivatedRoute, private titleService: Title, private meta: Meta) {}
```

そして同じくapp.component.ts (もしくは独自のブートストラップコンポーネントにて)にてngOnInit(){}に以下のメソッドを追記して、

```typescript
ngOnInit() {
      //app.route.tsからmeta tagデータを引っ張り出してくるメソッド
      this.router.events.pipe(
        filter((event) => event instanceof NavigationEnd),
        map(() => this.route),
        map((route) => {
          while (route.firstChild) route = route.firstChild;
          return route;
        }),
        filter((route) => route.outlet === 'primary'),
        mergeMap((route) => route.data)).subscribe((event) => {
          this.updateDescription(event['description'], event['keywords'], event['title'], event['twittercard'], event['twittersite'], event['twitterimage'], event['url']);
        });
}
```
最後におなじくapp.component.ts (もしくは独自のブートストラップコンポーネントにて)にて適当な場所に`updateDescription()`メソッドを追記。

```typescript
   // metaタグをアップデートするメソッド
   updateDescription(desc: string, keywords: string, title: string, twittercard: string, twittersite: string, twitterimage: string, url: string) {
    this.titleService.setTitle(title);
    this.meta.updateTag({ name: 'description', content: desc })
    this.meta.updateTag({ name: 'keywords', content: keywords })
    this.meta.updateTag({ name: 'twitter:card', content: twittercard })
    this.meta.updateTag({ name: 'twitter:site', content: twittersite })
    this.meta.updateTag({ property: 'og:url', content: url })
    this.meta.updateTag({ property: 'og:title', content: title })
    this.meta.updateTag({ property: 'og:description', content: desc })
    this.meta.updateTag({ property: 'og:image', content: twitterimage })
   }
```

これでGoogleのクローラーは拾ってくれるようになった。
TwitterカードなどSNS系のボットはまだSPAのJS動的画面描画に対応してないようだがまあ時間の問題だろうと用意しておいた。

<br>

参考：[Dynamically add meta description based on route in Angular](https://stackoverflow.com/questions/48330535/dynamically-add-meta-description-based-on-route-in-angular)


<br>