はじめに
この記事はAngular Advent Calendar 2018 15日目の記事です。
Webアプリケーションでよく使う入力系のUIに「日付の入力」があると思いますが
これがなかなかサポートするブラウザによっては使い物にならない場合が多く
それをカバーするために様々な日付入力用のライブラリが出ていると思います。
パッと思いつきレベルではjQuery系とかが豊富なイメージですが、
お仕事で作っているプロジェクトではAngular + Angular JSのハイブリッド環境で
「ここにさらにjQueryを入れる」という選択も微妙だったので
Angular Materialのdatepickerを調査として使ってみた記録になります。
日付入力のブラウザ間の違いを見てみる
Angular Materialを触り始める前に、ブラウザごとの <input type="date">
の
見た目や使い勝手の違いを整理していきたいと思います。
サポートしたいブラウザで最低限のことができれば、Materialを入れないほうが
バンドルサイズも減るだろうし…という感じのテンションで
MDNのドキュメントにあるサンプルで試してみました。
macOS
Safari | Chrome | Firefox |
---|---|---|
![]() |
![]() |
![]() |
macOSですが、標準で入っているSafariがカレンダーから選択するUIを提供しておらず、ちょっとガッカリです。
ちなみに、iOSのSafariはドラムロールのUIを提供しているので大丈夫です。
Chrome、Firefoxはカレンダーから選択するUIを提供しているので、良さそうですね。個人的にはFirefoxのUIが
スッキリしてて好印象です。
Windows 10
IE11 | Chrome | Edge |
---|---|---|
![]() |
![]() |
![]() |
IE11がSafari同様にカレンダーのUIを提供しておらず、残念感が出ています。
ChromeはmacOSと同じくカレンダーのUIを、EdgeもiOS SafariのようなUIが提供されます。
Firefoxのスクショを撮り忘れちゃいましたが、macOSで出ているので大丈夫そうな気がします。
IE11とSafariをサポートするWebサイトは対応が必須
macOSのSafari、WindowsのIE11では<input type="date">
で
カレンダー型のUIを出してくれないので何かしらの対応が必要になります。
何かの開始日を指定するような画面でユーザーに「yyyy-MM-dd
形式で入力してね」は
さすがに不親切すぎるのでカレンダー型のUIを提供したほうが良さそうです。
というわけで次のセクションからAngular Materialのdatepickerを触っていきます。
開発環境
お仕事で使っているのはAngular + Angular JSのハイブリッド環境(絶賛移行中)ですが
今回はサクッとやりたいことができるか検証したかったので、
新しいCLIプロジェクトを作成してみます。
(StackBlitzだといろんなブラウザで確認できなかった、気のせいかな…?)
Angular CLI: 7.1.1
Node: 8.11.3
OS: macOS 10.14.2
AngularCLIプロジェクトを作成
まずは空のAngularプロジェクトをCLIで生成
ng new angular-material-test --routing --style=styl
試すだけだからルーティングとかいらないですが、いつものクセです。
Angular Materialの導入
CLIプロジェクトなので ng add @angular/material
と入れるだけでほぼ終わります。
途中でマテリアルデザインのカラーパレットを選ばされるので、デフォルトから選ぶもよし、オリジナルを設定するもよしです。
昔Materialを導入しようとしたときはもっとステップあったのに、めちゃくちゃ簡単になってますね。ng add
最高。
なんとなく、カラーテーマをオリジナルで設定したかったので、そこだけいい感じに。
http://takasdev.hatenablog.com/entry/2017/10/08/125524 を参考にしながら
http://mcg.mbitson.com/#!?mcgpalette0=%23489bc6&themename=mcgtheme で色を作って組み込みました。
Datepickerを実装する
Inputそのものにマテリアルデザインを適用したくなかったので
ボタンでカレンダーを開く、みたいな実装を行いました。CSSでbutton
は透明にして
.date-input
に被せるような感じにしています。
// ...
import { FormsModule } from '@angular/forms';
import { MatDatepickerModule, MatNativeDateModule } from '@angular/material';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
FormsModule. // 追加
MatDatepickerModule, // 追加
MatNativeDateModule // 追加
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
<div class="date-input-container">
<input class="date-input" [matDatepicker]="picker" [(ngModel)]="date" placeholder="Choose a date">
<mat-datepicker #picker></mat-datepicker>
<div class="button" (click)="picker.open()"></div>
</div>
これだけで、Angular Materialのdatepickerを使えるようになりました。
上で出したどのブラウザでも同じUIで日付を選択できるようになって、統一感が増しました
[(ngModel)]
ではDate
型で入ってくるのも嬉しいポイントでした。いちいちパースとかしなくていいのも嬉しい!
日本語化する
このままでも十分最高な日付入力UIですが、サービスによって
はカレンダーの表示が英語だと厳しいところもあるかと思います。
inputの中身も14/12/2018
とかいう日本人に馴染みがない表記になっちゃうし。
そこで、サクッと
ドキュメントを参考に app.module.ts
に以下のような記述を追加したところ
providers: [
{provide: MAT_DATE_LOCALE, useValue: 'ja-JP'}
]
あとは「◯日」っていう表示がちょっとゴチャついて見えてしまうので
英語のときみたいに「1, 2, 3, 4」という表記に戻してあげたいと思います。
// NativeDateAdapterの一部を上書きしたJPDateAdapterを作る
export class JPDateAdapter extends NativeDateAdapter {
getDateNames(): string[] {
return Array.from(Array(31), (v, k) => `${k + 1}`);
}
}
providers: [
{provide: DateAdapter, useClass: JPDateAdapter}
]
いい感じになりました!
日付入力をアツくカスタマイズする
入力可能な日付を制限する
Angular Materialならいつからいつまで、といった範囲を指定して
ユーザーに日付を入力させることが可能です。
minDate: Date;
maxDate: Date;
ngOnInit () {
// 今日の日付から…
this.minDate = new Date();
// 一週間後の日付を指定したい
const date = new Date();
date.setDate(this.minDate.getDate() + 7);
this.maxDate = date;
}
<input
class="date-input"
[min]="minDate"
[max]="maxDate"
[(ngModel)]="date"
[matDatepicker]="picker"
placeholder="Choose a date">
カレンダーを開いたときに最初に出す日付
カレンダーを最初に表示したときは今日の日付じゃなくて、特定の日がいい〜
みたいなケースもパパっとできちゃいます。
<mat-datepicker [startAt]="startAt" #picker></mat-datepicker>
startAt = new Date(1996, 2, 10)
カレンダーを開いたときに最初に表示させるUI
誕生日を選ばせるんだし、最初は年を選ばせたいなあ、みたいなケースにもバッチリです。
<!-- 'month'(月表示) | 'year'(年表示) | 'multi-year'(複数年表示) -->
<mat-datepicker [startView]="'multi-year'" #picker></mat-datepicker>
まとめ
- 日付入力の闇をまるっと吸収してくれるAngular Material最高かよ
- Angular Material、サンプルが充実してて最高だった
- APIドキュメントを見ているだけでも面白い 🕶️
明日のAngular Advent Calendar 2018 担当は @shira_ さんです!