こんにちは。
今回は、RailsでStimulusJSとTOAST UIを使ってカレンダーを表示してみます。
StimulusJSとは
StimulusJSは、HotwireのJavaScriptフレームワークです。
HTMLのdata属性を使って、JavaScriptを管理するのでコードがシンプルかつ軽量になります。
Rails7.0からは、デフォルトでStimulusJSが導入されています。
参考: https://stimulus.hotwired.dev/
TOAST UIとは
TOAST UIは、韓国のNHN社が開発しているオープンソースのJavaScriptライブラリです。
TOAST UIは、様々な種類のUIコンポーネントを提供しています。
今回は、TOAST UIのカレンダーを使ってみます。
実装
今回は、StimulusJSが使える前提での実装になります。
セットアップ
まずは、TOAST UIのカレンダーを使えるようにします。
./bin/importmap pin @toast-ui/calendar
上記コマンドで、config/importmap.rb
に以下が追加されます。
pin "@toast-ui/calendar", to: "https://ga.jspm.io/npm:@toast-ui/calendar@2.1.3/dist/toastui-calendar.mjs"
pin "tui-date-picker", to: "https://ga.jspm.io/npm:tui-date-picker@4.3.3/dist/tui-date-picker.js"
pin "tui-time-picker", to: "https://ga.jspm.io/npm:tui-time-picker@2.1.6/dist/tui-time-picker.js"
CSSも読み込むために、app/views/layouts/application.html.haml
に以下を追加します。
%link{href: "https://uicdn.toast.com/calendar/latest/toastui-calendar.min.css", rel: "stylesheet"}/
上記はHTMLのhead
内に追加してください。
StimulusJSのコントローラーを作成する
次に、StimulusJSのコントローラーを作成します。
import { Controller } from "@hotwired/stimulus";
import Calendar from "@toast-ui/calendar";
export default class extends Controller {
static targets = ["calendar"]
static values = { events: Array }
connect() {
this.calendar = new Calendar(this.calendarTarget, {
defaultView: 'month',
isReadOnly: true,
scheduleView: true,
template: {
time(event) {
const { start, title } = event;
const date = new Date(start);
const hour = date.getHours().toString().padStart(2, '0');
const minute = date.getMinutes().toString().padStart(2, '0');
const time = `${hour}:${minute}`;
return `<span>${time} ${title}</span>`;
},
allday(event) {
return `<span style="color: gray;">${event.title}</span>`;
},
},
useDetailPopup: true,
});
this.eventsValue.forEach((event) => {
this.calendar.createEvents([
{
id: event.id,
calendarId: '1',
title: event.title,
category: 'time',
dueDateClass: '',
start: event.start,
end: event.end,
},
]);
});
}
next() {
this.calendar.next();
}
prev() {
this.calendar.prev();
}
}
上記のコントローラーでは、以下のことを行っています。
- calendarTargetにカレンダーを表示する
- eventsValueに入っているイベントをカレンダーに表示する
- 翌月に移動する
next
メソッドを定義する - 前月に移動する
prev
メソッドを定義する
eventsValueは、以下の形式を想定しています。
こちらは後ほど、Railsのコントローラーから渡すようにします。
[
{
id: 1,
title: 'イベント1',
start: '2021-01-01T00:00:00+09:00',
end: '2021-01-01T00:00:00+09:00',
},
{
id: 2,
title: 'イベント2',
start: '2021-01-02T00:00:00+09:00',
end: '2021-01-02T00:00:00+09:00',
},
]
Viewを作成する
次に、Viewを作成します。
.h-screen{ data: {controller: 'calendar', 'calendar-events-value' => @events.to_json}}
.p-4.flex.justify-between
%button.p-2.rounded-full.bg-blue-500.text-white{ class: 'hover:bg-blue-600', data: {action: 'click->calendar#prev'}}
%svg.w-6.h-6{:fill => "none", :stroke => "currentColor", "stroke-width" => "1.5", :viewbox => "0 0 24 24", :xmlns => "http://www.w3.org/2000/svg"}
= render 'svgs/chevron_left'
%button.p-2.rounded-full.bg-blue-500.text-white{ class: 'hover:bg-blue-600', data: {action: 'click->calendar#next'}}
%svg.w-6.h-6{:fill => "none", :stroke => "currentColor", "stroke-width" => "1.5", :viewbox => "0 0 24 24", :xmlns => "http://www.w3.org/2000/svg"}
= render 'svgs/chevron_right'
.h-full{ data: {'calendar-target' => 'calendar'}}
上記のコードでは、以下のことを行っています。
- Stimulusのcalendarコントローラーを呼び出す
- カレンダーに表示するイベントを渡す
- カレンダーの前月に移動する
prev
メソッドを呼び出すボタンを作成する - カレンダーの翌月に移動する
next
メソッドを呼び出すボタンを作成する - カレンダーを表示する
Railsのコントローラーを作成する
最後に、Railsのコントローラーを作成します。
class CalendarsController < ApplicationController
def show
@events = [
{
id: 1,
title: 'イベント1',
start: '2021-01-01T00:00:00+09:00',
end: '2021-01-01T00:00:00+09:00',
},
{
id: 2,
title: 'イベント2',
start: '2021-01-02T00:00:00+09:00',
end: '2021-01-02T00:00:00+09:00',
},
]
end
end
上記のコードでは、カレンダーに表示するイベントを定義しています。
ここをデータベースから取得するようにすれば、データベースに保存されているイベントをカレンダーに表示することができます。
動作確認
こんな感じのカレンダーが表示されれば成功です。
(イベントは都合上表示させていませんが、イベントも表示されます。)
まとめ
今回は、RailsでStimulusJSとTOAST UIを使ってカレンダーを表示してみました。
StimulusJSは外部のライブラリとも相性が良く、簡単に導入することができますね。
個人的にはnode_modulesがないことでもすごく便利に感じています。
今回はこのあたりで。