📆

Phoenix LiveViewによるDate Picker UIの実装

2024/03/15に公開

この記事について

2024年3月15日に東京浜松町・大門でElixir/Phoenix 勉強会+採用事例紹介と題するオフラインイベントが開催されました。

この記事は、私(黒田)が行った発表「Phoenix LiveView講座(20分)」の題材である DaimonDataPicker の実装手順を解説したものです。

開発環境

  • Elixir 1.16.1
  • Phoenix 1.7.11

骨格の作成

mix phx.new --no-ecto --no-dashboard --no-mailer daimon_date_picker
cd daimon_date_picker
  • ebd15a6 mix phx.new --no-ecto --no-dashboard --no-mailer daimon_date_picker

準備作業

README.md を作成し、コントローラ関連のファイル群を削除。

  • 302d819 Update README.md
  • 5c2d785 Remove controllers; Clean up router.ex

Phoenix LiveViewで空白ページを表示

lib/daimon_date_picker_web/live ディレクトリを作成し、そこに home_live.ex を作成。中身は次の通り:

defmodule DaimonDatePickerWeb.HomeLive do
  use Phoenix.LiveView

  def mount(_params, _session, socket) do
    {:ok, socket, layout: {DaimonDatePickerWeb.Layouts, :app}}
  end
end

また、同じディレクトリに home_live.html.heex を作成:

<div>home_live.html.heex</div>
  • dcdf7e3 Create DaimonDatePicker.HomeLive and an empty heex template
  • 48e77a8 Apply :app layout to the home page

Date Picker UIの実装①

日付入力欄を設置し、その内部をクリックすると、Date Pickerというテキストの表示・非表示が切り替わるところまで実装。

  • 159a710 Show text input with today's date as the initial value
  • a6f815e Impl. toggle_date_picker event handler

Date Picker UIの実装②

Date Picker UIのビジュアルデザインが完成。

  • c85e100 Show current month and prev/next buttons
  • 5db49de Show week days
  • a5ee92f Show all days for the current month

Date Picker UIの実装③

Prevボタン、Nextボタンで socket.assigns.current_month の値を切り替えるところまで実装。

  def handle_event("prev_month", _params, socket) do
    prev_month =
      socket.assigns.current_month
      |> Date.add(-1)
      |> Date.beginning_of_month()

    socket = assign(socket, :current_month, prev_month)
    {:noreply, socket}
  end

  def handle_event("next_month", _params, socket) do
    next_month =
      socket.assigns.current_month
      |> Date.end_of_month()
      |> Date.add(1)

    socket = assign(socket, :current_month, next_month)
    {:noreply, socket}
  end

Dateモジュールの関数群を活用して前月あるいは翌月の初日を作り、socket.assigns.current_month にセットしている。

  • 9934f48 Impl. prev_month and next_month event handlers

Date Picker UIの実装④

カレンダー内の日付がクリックされると、socket.assigns.selected_date に日付がセットされるところまで実装。

  def handle_event("select_date", %{"day" => day} = _params, socket) do
    eom = Date.end_of_month(socket.assigns.current_month)

    selected_date =
      case Integer.parse(day) do
        {d, ""} when d in 1..eom.day ->
          %{socket.assigns.current_month | day: d}

        _ ->
          socket.assigns.current_month
      end

    socket =
      socket
      |> assign(:selected_date, selected_date)
      |> assign(:activated, false)

    {:noreply, socket}
  end

文字列として送られてくる "day" パラメータの値を Integer.parse/2 で整数に変換し、それを socket.assigns.current_monthday フィールドにセットしている。"day" パラメータは外部から送られてくる値であるため、その月の日付として正しいことを念のため確認している。

  • 2e175ac Impl. select_date event handler

Discussion