pickadate.jsでカレンダーを表示

日付登録の機能をつけたくて最初はFullCalendarを使っていたのですが、レスポンシブ対応ができなかったので色々探してみた結果、このライブラリを実装したら思ったよりも格好いいフォームができました。
献血のアプリケーションを作っていて、献血をした日と次回の献血の予定日の２項目に実装しました。

## 環境
Rails 5.2.3

## 留意点
cssとhtmlとJSはそれぞれscssとhamlとjQueryで記述しています。

## 実装
### pickadate.jsを使うために
[pickadate.js](https://amsul.ca/pickadate.js/)からダウンロードして、必要なファイルを読み込ませます。
[必要なファイルの参考Qiita](https://qiita.com/Yuta_Fujiwara/items/e80fb931af623bd8e73e)

```application.html.haml
%link{:href => "/css/default.css", :rel => "stylesheet"}
%link{:href => "/css/default.date.css", :rel => "stylesheet"}
%script{:src => "/pickadate/picker.js"}
%script{:src => "/pickadate/picker.date.js"}
%script{:src => "/pickadate/legacy.js"}
%script{:src => "/pickadate/lang-ja.js"}
```
自分の場合、assets下にディレクトリとファイルを置いたらコンソールでエラーが１０個近く出てきたので、結果的にpublic下に置いて、パスを上記のようにしました。
ちなみに、lang-ja.jsは他の記事を参考にして作成したものなので、ダウンロードしたものの中には入っていません。
[lang-ja.js](https://qiita.com/Yuta_Fujiwara/items/e80fb931af623bd8e73e)
↓ファイルの置き場所

- public
  - css(このディレクトリは自作)
     - default.css
     - その他必要なcssファイル
  - pickadate(このディレクトリは自作)
     - picker.js
     - その他必要なjsファイル

### カレンダーの表示まで
```new.html.haml
= f.text_field :donation_day, placeholder: "クリックしてください", id: "donation_day"
```
```show.html.haml
= f.text_field :next_date, placeholder: "クリックしてください", id: "schedule"
```
form_forを使用しているのでこのような記述になっています。
カレンダーを表示させたいところにそれぞれidを追加します。

```pickadate.js
$(document).on('turbolinks:load', function() {
  $(function() {
    $(window).on("focus", function () { // これがないと画面に戻った時に勝手にカレンダーが表示される
      $(document.activeElement).blur();
    });
    $('#schedule').pickadate({ // 選択できる最低限
      min: 0
    });
    $('#donation_day').pickadate({ // 選択できる最大限
      max: 0
    });
  }
  );
});
```
で、重要なのがこっち。
2つに分けて説明します。

```pickadate.js
$(document).on('turbolinks:load', function() {
  $(function() {
    $(window).on("focus", function () { // これがないと画面に戻った時に勝手にカレンダーが表示される
      $(document.activeElement).blur();
    });
  });
});
```
最終的に一番苦労したのがこれ。
この記述がないと、テキストボックスを選択した状態で他の画面に遷移して、元の画面に戻ってくると、クリックしたわけでもないのに勝手にカレンダーが表示されました。
[pickadate.js 勝手にウィンドウが開く](https://teratail.com/questions/138624)
[JavaScript でフォーカスの当たっているボタンなどからフォーカスを外す](https://mseeeen.msen.jp/javascript-blur-and-focus-with-buttons/)

・記述がない場合
ここでは、
カレンダー表示→カレンダー閉じる→画面遷移→元の画面に戻る→勝手にカレンダーが表示
という順番で動作しています。
![demo](https://gyazo.com/de4707c782293241b06742d728f2da7b/raw)

・記述がある場合
画面を戻してもカレンダーは勝手に表示されません。
![demo](https://gyazo.com/6cc449ade0bc30684771036b0511e932/raw)


```pickadate.js
$(document).on('turbolinks:load', function() {
  $(function() {
    $('#schedule').pickadate({ // 選択できる最低限
      min: 0
    });
    $('#donation_day').pickadate({ // 選択できる最大限
      max: 0
    });
  });
});
```
それぞれ、カレンダーを表示させたいidを指定します。
min: 0　は選択できる最低限のところ、0だと「今日」になります。
max: 0　は選択できる最大限のところ、0だと「今日」になります。
上のGIFでカレンダーが表示された時にグレーになっている部分があると思いますが、それがmin: 0で設定した結果です。

オプションはほかにも色々あります。

~~本当は土日をそれぞれ、青、赤の色にしたかったのですが未だ実装できてないのでわかり次第追記します。~~

2019/10/25 追記
やっと土日に色をつけられた。

```pickadate.js
$(document).on('turbolinks:load', function() {
  $(function() {
    function css_add() { // ページロード時と左右の矢印を押した時に呼び出す関数
      var sun = $('.picker__weekday:first') // firstが日曜日
      var sut = $('.picker__weekday:last') // lastが土曜日
      sun.attr('id', 'sun')
      sut.attr('id', 'sut')

      $('#sun').css({
        'background-color': 'red',
        'color': 'white'
      })
      $('#sut').css({
        'background-color': 'blue',
        'color': 'white'
      })
    }

    css_add();

    $('.picker__holder').on("click", ".picker__nav--next, .picker__nav--prev", function() {
      css_add();
    });
  });
});
```

検証モードでクラス名などを調べたところ、picker__holderが一番外枠になっていそうだったのでここをイベント発火ポイントに指定。(逆にdocumentだと動かない)
クリックイベントでクリックする場所をpicker__nav--next(次の月の矢印)、picker__nav--next(前の月の矢印)にして、css_add()関数を呼び出す。
で、困ったのが、曜日に同じクラス名(picker__weekday)が当てられているのでどうしようかと。(これだと同じクラスにcssを当てたところで全部が赤か青になってしまう)
調べたら、:firstと:lastで要素の最初と最後を取れるみたいなので、これで土日を指定して、attrメソッドでidを付与しました。
最後に、それぞれのidにbackground-colorを設定しました。(ついでに文字色も白に変更)

#### 実行結果
![demo](https://gyazo.com/013d617c7ad5abf04fd63b949918c45b/raw)

最終的なpickadate.jsの記述

```pickadate.js
$(document).on('turbolinks:load', function() {
  $(function() {
    $(window).on("focus", function () { // これがないと画面に戻った時に勝手にカレンダーが表示される
      $(document.activeElement).blur();
    });

    $('#schedule').pickadate({ // 選択できる最低限
      min: 0
    });
    $('#donation_day').pickadate({ // 選択できる最大限
      max: 0
    });

    function css_add() { // ページロード時と左右の矢印を押した時に呼び出す関数
      var sun = $('.picker__weekday:first') // firstが日曜日
      var sut = $('.picker__weekday:last') // lastが土曜日
      sun.attr('id', 'sun')
      sut.attr('id', 'sut')

      $('#sun').css({
        'background-color': 'red',
        'color': 'white'
      })
      $('#sut').css({
        'background-color': 'blue',
        'color': 'white'
      })
    }

    css_add();

    $('.picker__holder').on("click", ".picker__nav--next, .picker__nav--prev", function() {
      css_add();
    });
  });
});
```


## 注意点
データベースに保存するときは、date型だと失敗したのでstring型にしています。