Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
20
Help us understand the problem. What is going on with this article?
@pittanko_pta

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

More than 1 year has passed since last update.

はじめに

この記事は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_ さんです!

20
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
pittanko_pta
Perfumeと乃木坂・欅坂が好きです。フロントエンドの人。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
20
Help us understand the problem. What is going on with this article?