LoginSignup
1
0

More than 1 year has passed since last update.

jQuery UIのdatepickerを使って特定の日付だけマーキングさせる

Posted at

0. はじめに

 少しずつ開発している日報アプリのlytnote。日報を毎日記入していくけど、なにか良いフィードバックが欲しいところ。ラジオ体操のスタンプカードのような、githubの草のような。

 というわけでカレンダーをつくって、日報があったところが塗られるようにした。

1. datepickerの導入

 カレンダーを自前で作るのはかなり大変なので、有名なライブラリを使うことにした。ここはjQuery UIのdatepickerだろう。

 導入は簡単で、CDNを貼るだけだった。以下のサイトからここからできる。
https://releases.jquery.com/

私の場合はapplication.html.erbに貼った。

app/views/layouts/application.html.erb
<!-- 略 -->
<head>
<title>lytnote</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>

<!-- 略 -->
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<!-- 略 -->
</head>

あとはviewファイルとjsファイルは以下のようにする。

app/views/reports/index.html.erb
<!-- 略 -->
<div id="datepicker"></div>
<!-- 略 -->
app/javascript/home.js
$(document).on("page:load turbolinks:load", function() {
//略
    $( "#datepicker" ).datepicker();
});
app/javascript/packs/application.js
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

require("jquery")
require("@nathanvda/cocoon")

require ('home')

これでdatepickerが表示される。

2.「特定の日」を取得してデータを受け渡す

 日報一覧の画面が出た時点で、特定の日、つまりは日報が作成された日付の配列を取得する。コントローラを以下のようにする。

app/controllers/reports_controller.rb
def index
    @reports= Report.includes(:report_items).where(user_id: current_user.id).page(params[:page]).order(reported_on: :desc)
    reported_days_original = @reports.map(&:reported_on)
    reported_days = reported_days_original.map{
      |days| days.strftime("%F")
    }
    @reported_days = reported_days.to_json
end

#略...

 @reports云々は気にしなくていい。それ以降が重要だ。

railsでは指定したカラムのデータを取得するのに、pluckというメソッドがある。しかし、@reports.pluck(:reported_on) とは使用できない。(使用できるけど値が重複してしまったりする。)

以下のような理由かららしい。

知っておくと良い注意点は、リレーションオブジェクトにincludesがあると、eager loadingが不必要なクエリにおいてでも、pluckがeager loadingを引き起こすことです。
https://railsguides.jp/active_record_querying.html#pluck

 このeager loadingが詳しくわからなかった。ひとまずはmapで置き換えることにした。

  • days.strftime("%F")によってreported_daysの配列の要素を2023-01-01のように変換している。
     
  • to_jsonを使って、railsからJSへデータの受け渡しを行えるように整形しておく。

 viewファイルに以下を追記する。

app/views/reports/index.html.erb
<!-- 略 -->
<input type="hidden" id="reported" value="<%= @reported_days %>">
<div id="datepicker"></div>
<!-- 略 -->

inputタグをhiddenにして記入しておくと、表示せずにデータだけ受け渡すことが可能となる。

3. カレンダーの特定の日付にCSS classを付与

 特定の日付にだけclassを付与させる場合はbeforeShowDay メソッドを使う。functionと戻り値の記述方法は以下のようにする。

$( "#datepicker" ).datepicker({
    beforeShowDay: function(date) {
        return [false, '', ''];
    }
});

functionのなかのdateには日付が入っている。Chromeのデベロッパーツールで確認すると、一ヶ月とその前後3~4日を一つずつループして確認しているようだ。戻り値は配列で記述しなければいけない。それぞれ

[日付選択の可否(true/false),CSSのclass名,日付にカーソルをあてると出てくる値]

となる。うしろの二つは""と空白にしても構わない。

もう少し詳しく書くと以下になる。

app/javascript/home.js
$(document).on("page:load turbolinks:load", function() {
//略...

 let reportedDays_json = document.getElementById('reported').value;
  if (reportedDays_json !== null) {
    let reportedDays = JSON.parse(reportedDays_json);
    $( "#datepicker" ).datepicker({
      beforeShowDay: function(date) {
          let formattedDay = dayjs(date).format('YYYY-MM-DD');
          if (reportedDays.indexOf(formattedDay) != -1) {
            return [false, 'reported-days', ''];
          }else{
            return [false, '', ''];
          }
      }
    });
  }
});

reportedDaysは日報が登録された日付の配列となる。beforeShowDayメソッドで、ひとつひとつのdateがそのなかに入っているかどうか確認する。入っていたらreported-days classを付与させる。

dayjs(date).formatは dayjsを利用している。導入方法は以下が詳しい。

4. CSSを変更

 今のままだとデフォルトのdatepickerのデザインになってしまう。デザインを確かめながらCSSを変更していく。

app/assets/stylesheets/application.scss
/* 略..*/

.ui-datepicker-next:hover,.ui-datepicker-prev:hover {
  background: none;
}

.ui-state-default,
.ui-widget-content .ui-state-default,
.ui-widget-header .ui-state-default,
.ui-button,
html .ui-button.ui-state-disabled:hover,
html .ui-button.ui-state-disabled:active {
  border: 0px;
  background-image: none;
  background:inherit;
	font-weight: normal;
	color: #182736;
}
.ui-state-disabled,
.ui-widget-content .ui-state-disabled,
.ui-widget-header .ui-state-disabled {
	opacity: 1;
	filter:none; /* support: IE8 */
}

これで背景のグラデーションが消えて、すこし今風のデザインになる。こだわると時間がかかりそうなので、一旦はここまで。

4. 完成画面

スクリーンショット 2023-02-13 5.16.56.png

 

5. おわりに

 少しずつ自分の思うサービスになってきた気がする。これからも開発を続けるぞ。

 今回の機能はまだ本番環境には反映させてません。もう少しいろいろなおしてからあげます。

1
0
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
1
0