DatePipe を IE11 等で動かすと変な表示になる件に対応する
Angular で日付をフォーマット表示する場合、DatePipe
を利用します。
Pipe とは、AngularJS で言う Filter で、構文も変わっていません。
<p>Date: {{ now | date:'yyyy-MM-dd HH:mm:ss' }}</p>
さて、このシンプルなフィルターですが、ブラウザごとに異なる表示になってしまいます。 以下の URL を開いてみてください。
https://plnkr.co/edit/lVCkJcIopxTOk5L9iyCm?p=preview
どうでしたか ? IE11, Edge の方は上手く表示されていないのではないかと思います。
Expected: 2017-04-01 12:34:56 Actual: 2017-04-01 12:00:4/1/2017 12:34:56 PM:4/1/2017 12:34:56 PM
どーやったらこんな表示になるんだ・・・。
どうやら不具合っぽい
もちろん、Issue は立っています。
また、ドキュメントには以下の通り書いてあります。
WARNINGS:
- this pipe is marked as pure hence it will not be re-evaluated when the input is mutated. Instead users should treat the date as an immutable object and change the reference when the pipe needs to re-run (this is to avoid reformatting the date on every change detection run which would be an expensive operation).
- this pipe uses the Internationalization API. Therefore it is only reliable in Chrome and Opera browsers.
重要なのは最後の 1 文。 DatePipe は I18n API を利用しているので、Chrome と Opera でのみ信頼性があります。
Workaround: moment を利用する
Issue にもコメントがありますが、Workaround として以下 2 つが提示されています。
date:'short'
やdate:'shortDate'
はちゃんと動くよ !moment
を使った Pipe を定義しよう !
任意のフォーマットで表示したいのに date:'short'
は動くと言われても困ります。
ということで、 moment
を使った Pipe を定義しましょう。
1. npm install
はじめに、moment
への依存設定を追加します。
npm install moment --save
なお、TypeScript の型定義は moment
に含まれているため、別途 @types/moment
を導入する必要はありません。(導入すると、追加しなくていいよと警告が表示されます。)
2. Pipe 実装
以下のように Pipe を実装します。
angular-cli をご利用の方は ng g pipe moment.pipe
で雛形を生成できます。
import { Pipe, PipeTransform } from '@angular/core'; import * as moment from 'moment'; // (1) @Pipe({ name: 'moment' // (2) }) export class MomentPipe implements PipeTransform { transform(value: any, args?: any): any { if (value === undefined || value === null) return '# value is undefined or null #'; // (3) if (args === undefined || args === null) return '# args is undefined or null #' // (4) let s = moment(value).format(args); return s; } }
No | 解説 |
---|---|
(1) | moment を参照します |
(2) | name に指定した名前で Pipe を利用できます |
(3) | 日付 or 日付形式の文字列が定義されているかのチェックです |
(4) | 引数 (フォーマット文字列) が指定されているかのチェックです |
3. Module 登録
Pipe を実装したら、忘れずに Module に登録します。
angular-cli を使って生成した場合は追加されているかも。
以下は、Pipe をまとめた PipesModule
を定義した場合の例です。
// import 省略 @NgModule({ imports: [ CommonModule ], exports: [ MomentPipe // (1) ], declarations: [ MomentPipe // (2) ] }) export class PipeModule { }
No | 解説 |
---|---|
(1) | PipeModule を import したモジュールで MomentPipe を利用したい場合、exports に追加する必要があります。 |
(2) | declarations に MomemtPipe を追加し、モジュール内で利用できるようにします。 |
まとめ
IE11 等で DatePipe でフォーマット指定がうまくいかないため、代替案として moment を利用した Pipe を作成しました。
DatePipe で困っている方は参考にしてみてください。