33
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AngularAdvent Calendar 2018

Day 15

date inputの救世主!? Angular Materialのdatepickerを使ってみた

Posted at

はじめに

この記事は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
mac safari.png mac chrome 71.png mac firefox.png

macOSですが、標準で入っているSafariがカレンダーから選択するUIを提供しておらず、ちょっとガッカリです。
ちなみに、iOSのSafariはドラムロールのUIを提供しているので大丈夫です。
Chrome、Firefoxはカレンダーから選択するUIを提供しているので、良さそうですね。個人的にはFirefoxのUIが
スッキリしてて好印象です。

Windows 10

IE11 Chrome Edge
windows ie11.png windows chrome 70.png windows edge.png

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に被せるような感じにしています。

app.module.ts
// ...
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 { }
app.component.html
<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で日付を選択できるようになって、統一感が増しました :clap: :clap:
[(ngModel)]ではDate型で入ってくるのも嬉しいポイントでした。いちいちパースとかしなくていいのも嬉しい!

日本語化する

このままでも十分最高な日付入力UIですが、サービスによって
はカレンダーの表示が英語だと厳しいところもあるかと思います。
inputの中身も14/12/2018とかいう日本人に馴染みがない表記になっちゃうし。
image.png

そこで、サクッと
ドキュメントを参考に app.module.ts に以下のような記述を追加したところ

app.module.ts
providers: [
  {provide: MAT_DATE_LOCALE, useValue: 'ja-JP'}
]
スクリーンショット 2018-12-13 23.56.25.png 日本語になりました 👏👏

あとは「◯日」っていう表示がちょっとゴチャついて見えてしまうので
英語のときみたいに「1, 2, 3, 4」という表記に戻してあげたいと思います。

jp-date-adapter.ts
// NativeDateAdapterの一部を上書きしたJPDateAdapterを作る
export class JPDateAdapter extends NativeDateAdapter {
  getDateNames(): string[] {
    return Array.from(Array(31), (v, k) => `${k + 1}`);
  }
}
app.module.ts
providers: [
   {provide: DateAdapter, useClass: JPDateAdapter}
]
image.png

いい感じになりました!

日付入力をアツくカスタマイズする

入力可能な日付を制限する

Angular Materialならいつからいつまで、といった範囲を指定して
ユーザーに日付を入力させることが可能です。

app.component.ts
minDate: Date;
maxDate: Date;

ngOnInit () {
  // 今日の日付から…
  this.minDate = new Date();

  // 一週間後の日付を指定したい
  const date = new Date();
  date.setDate(this.minDate.getDate() + 7);
  this.maxDate = date;
}
app.component.html
<input
  class="date-input"
  [min]="minDate"
  [max]="maxDate"
  [(ngModel)]="date"
  [matDatepicker]="picker"
  placeholder="Choose a date">

カレンダーを開いたときに最初に出す日付

カレンダーを最初に表示したときは今日の日付じゃなくて、特定の日がいい〜
みたいなケースもパパっとできちゃいます。

app.component.html
 <mat-datepicker [startAt]="startAt" #picker></mat-datepicker>
app.component.ts
startAt = new Date(1996, 2, 10)

カレンダーを開いたときに最初に表示させるUI

誕生日を選ばせるんだし、最初は年を選ばせたいなあ、みたいなケースにもバッチリです。

app.component.html
<!-- 'month'(月表示) | 'year'(年表示) | 'multi-year'(複数年表示) -->
 <mat-datepicker [startView]="'multi-year'" #picker></mat-datepicker>

まとめ

  • 日付入力の闇をまるっと吸収してくれるAngular Material最高かよ :beers:
  • Angular Material、サンプルが充実してて最高だった :hugging:
  • APIドキュメントを見ているだけでも面白い 🕶️

明日のAngular Advent Calendar 2018 担当は @shira_ さんです!

33
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?