エンジニアのはしがき

プログラミングの日々の知見を書き連ねているブログです

日付入力フォームはflatpickrがおすすめ

f:id:tansantktk:20210601205157p:plain

巷には様々な日付入力フォームのライブラリが溢れていますが その中でも先日導入したflatpickrが個人的に気持ちよく動いてくれたので紹介したいと思います!

flatpickrとは

flatpickr.js.org

github.com

npm、CDNで公開されているjsライブラリです。 軽量で記述しやすくjQueryにも依存しません。(ここが個人的に嬉しい)

最近はjsライブラリはフロントエンドフレームワークと併用することが多いかと思いますが、CSSセレクタでflatpickr化したいinput要素を指定するだけのシンプルな記述で済むので、フレームワークと競合するケースは少ないと思います。

flatpickrでできること

  • 日付の単日指定
  • 日付の期間指定
  • 指定日、指定期間の制限
  • 時刻指定
  • 表示スタイルの選択
  • 日本語表示 相当凝ったことをしたいなら別ですが、単純に日付、時刻をユーザーに入力させる用途であるなら検討して良いと思います。

使い方

環境

今回は私がいつも使うAngularを例にしています。

Node.jsをコアに動くフレームワークなら似た書き方になると思いますが各自動作確認いただければと思います。

インストール

何はともあれまずはnpm installします。

$ npm install flatpickr

CSSの読み込み設定

Angularの場合はflatpickrのCSSを別途ロードするように追記が必要になりますので、angular.jsonに下記を追記します。

angular.json

{
  ...
    "styles": [
      // cssをロード
      "node_modules/flatpickr/dist/flatpickr.min.css"
      ...
    ],
  ...
}

ロケール設定

flatpickrはデフォルトだと日付入力フォームの全てが英語で表示されます。 flatpickrで表示させる言語を他言語に変更したい場合は、任意の箇所でflatpickr.localize(...)を実行し、ロケールを読み込ませる必要があります。

なお今回はグローバルにロケール設定をしていますが、それぞれの日付入力フォーム事にロケール指定も可能です。

Localization - flatpickr

下記は日本語表示にしたい場合の例です。app.component.tsである必要性はありません。 システム構成に合わせてロードする箇所は検討下さい。

app.component.ts

...
// flatpickrの日本語化
import flatpickr from "flatpickr";
import { Japanese } from "flatpickr/dist/l10n/ja.js"
flatpickr.localize(Japanese);
...

flatpickrを配置する

まずは日付選択フォームをinput要素として配置します。 input要素にはCSSセレクタで一意に指定するためのidを付けておきます。

****.component.html

...
<input id="input-form" type="text">
...

次にcomponent側でテンプレートのinput要素にflatpickrを適用させる記述を書きます。

****.component.ts

import flatpickr from "flatpickr";
...
  ngAfterViewInit(): void {
    // input要素にflatpickrを適用する。CSSセレクタを第1引数で指定。
    flatpickr("#input-form", {
      // ロケール指定
      locale: 'ja',
    });
  }
...

flatpickrの基本はこれだけですのであとはデバッグ実行してみましょう。 input要素をクリックすれば入力フォームが出てくるはずです。

Angularで実装する際の注意点①

Angularで実装する際に注意しないといけない点は画面へのDOM要素描写が終わったタイミングで、flatpickr(...)を実行するよう記述する必要があるところです。

そのため上記の例では、DOM要素描写後に呼ばれるライフサイクルメソッドngAfterViewInit()内でflatpickr(...)を記述しています。

もしngOnInit内にflatpickr(...)を書いてしまうと、まだinput要素が描写されていない状態で実行されてしまうのでうまくflatpickrがinput要素に適用されません。

Angularで実装する際の注意点②

Angularの場合、*ngIfでDOM要素の表示/非表示を制御することがあると思いますが、 flatpickr化させたinput要素を含むDOM要素をngIfで制御してしまうと、ngIfの条件によりDOM要素が1度非表示になるとflatpickrが無効化されてしまいます。

無効化後にinput要素が再表示されたとしても、ただのinput要素として以降は扱われてしまいます。

例えば、下記のようなDOM要素はallowInputFormがfalseになってしまうとflatpickrが無効化されます。

<div *ngIf="allowInputForm">
    <input id="input-form" type="text">
</div>

対策

DOM要素をdisplay: noneにするclassを任意の変数にバインドすることで回避できます。 *ngIfがfalseになるとDOM要素はAngularによって削除されますが、display: noneを使うとDOM要素は機能しなくなり見えなくなるものの、DOMツリー上にはそのまま残り続けます。

下記はこの特徴を利用し、表示/非表示を切り替えるという方法です。

<!-- 例で記述しているclass`d-none`は`display: none`を適用するためのclassです。 -->
<div [class.d-none]="!allowInputForm">
    <input id="input-form" type="text">
</div>

日付選択されたらcomponentのプロパティに反映させる

Angularを使っているなら、componentのプロパティに状態を保持させたいと思います。 flatpickrではいくつかイベントフックを用意してくれています。

日付選択された時にプロパティに選択日付を代入する場合、下記のように書けます。

// componentのプロパティ
public dateProps: Date;
...
  ngAfterViewInit(): void {
    flatpickr("#input-form", {
      locale: 'ja',
      // onCloseは入力フォームが閉じられた時に発火する
      onClose: (selectedDates, dateStr, instance) => {
        if (selectedDates.length === 1) {
          // プロパティにユーザーが選択した日付を代入
          this.dateProps = selectedDates[0];
        }
      },
    });
  }
...

↓その他のイベントフックは公式ドキュメントをご覧ください。

Events & Hooks - flatpickr