2018年9月25日火曜日

AngularのPipeを使ってhtml(View)の表示を共通化する。


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

Angularのhtml(View)で変数を展開する場合、中括弧を二つ(double curly braces)で変数を囲みます。
<div>{{ targetDate }}</div>

さて、例えば、この「targetDate」変数に「2018/09/01」のような日付が設定されていて、
その日付が本日であれば『今日』、昨日だったら『昨日』と表示し、それ以外の時だけ、日付をそのまま表示するとします。
そんな時、どんな実現方法があるでしょうか?

「*ngIf」を使う?そもそもTypeScript側で判定しておく?色々とありますが、「*ngIf」を使うと煩雑になって、他に同じような表示箇所があったら、その度に記載する必要がありますし、APIから取得した値などは、html(View)側でリストのまま繰り返し処理を行う、
<ng-container *ngFor="let item of list">
  <div class="hoge">{{item.targetDate}}</div>
</ng-container>
という方法を使う事が多いので、TypeScript側で編集はしないんですよね。

まあ、『そんなのAPI側の責務でしょ』と言われたらそれまでですが、
表示内容に特化しているなら、フロントエンドでやるのも悪手では無いと思います。

さて、話が逸れてしまいましたが、こんな時に役に立つのが、AngularのPipe機能です。

簡単に言うと、htmlに表示する時に同時に変換処理も行い、表示内容を変えてしまう、と言う機能です。

早速使ってみましょう。
angular-cliを利用しているならば、
ng g pipe [path/name]
と言うコマンドでテンプレートを作成出来ます。

今回は、[path/name]の部分を pipe/change-date-format に変えます。
すると、以下のようなファイルが生成されます。
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'changeDateFormat'
})
export class ChangeDateFormatPipe implements PipeTransform {

  transform(value: string, args?: any): any {
    return null;
  }

}

この状態で、実装を行なっていきます。
今回、日付の編集・判定には、「moment」を使用します。
momentのインストールと使用方法は省きますが、実装結果は以下のようになります。
import { Pipe, PipeTransform } from '@angular/core';
import * as moment from 'moment';

@Pipe({
  name: 'changeDateFormat'
})
export class ChangeDateFormatPipe implements PipeTransform {

  transform(value: string, args?: any): any {
    const postDate = new Date(value);
    const postDateISO = moment(postDate.toISOString()).format('YYYYMMDD');
    const today = moment().format('YYYYMMDD');
    const yesterday = moment().subtract(1, 'days').format('YYYYMMDD');

    let displayDate: string = value;

    if (postDateISO === today) {
      displayDate = '今日';
    } else if (postDateISO === yesterday) {
      displayDate = '昨日';
    }

    return displayDate;
  }

}

処理は単純で、引数に送られてきた値を日付に変換、形式の統一、そして判定を行い、その日付が本日であれば『今日』、昨日だったら『昨日』、それ以外は日付をそのまま return しています。

Pipeの使い方は、
<div>{{ targetDate | changeDateFormat }}</div>
となります。@Pipe の name をvertical lineで変数に繋げて(Pipe)記載するだけです。簡単ですね。

大規模なプロジェクトになればなるほどPipeを上手く使うと、開発効率が上がります。
それでは、より良いAngularライフを!


0 件のコメント:

コメントを投稿