こんにちは!
プログラミング未経験文系出身、Elixirの国に迷い込んだ?!見習いアルケミストのaliceと申します。
今回はPhoenix1.7にScrivenerを導入してみた手順をまとめます。
なお、今回の記事は下記の記事を参考にPhoenix1.7でやってみたログです。
目次
1.Scrivener導入
2.ページネーションコンポーネントの作成(本記事)
目的
Phoenix1.7にScrivenerを導入してページネーションをつけたい
実行環境
Windows 11 + WSL2 + Ubuntu 22.04
Elixir v1.14.3
Erlang v26.0.2
Phoenix v1.7.10
LiveView v0.20.1
今回やりたいこと
Phoenix1.7.10/LiveView v0.20.1のプロジェクトにScrivenerを導入したい。
画面上に表示するページネーションコンポーネントを作る
元記事様の手順に従って作っていきます。
関数コンポーネントを作る
Phoenix1.7に合わせて置き場所をcore_components.ex
に置きました。
+ def paginator(assigns) do
+ ~H"""
+ <div>
+ <div>
+ <p>表示件数:</p>
+ <div>
+ <form phx-change="update_page_size">
+ <select name="page_size">
+ <option value="5" selected={@page_size == 5}>5</option>
+ <option value="10" selected={@page_size == 10}>10</option>
+ <option value="15" selected={@page_size == 15}>15</option>
+ <option value="20" selected={@page_size == 20}>20</option>
+ <option value="25" selected={@page_size == 25}>25</option>
+ </select>
+ </form>
+ </div>
+ <p><%= @total_entries %>件中 <%= @page_size * (@page - 1) + 1 %>~<%= @page_size * @page %>件を表示</p>
+ </div>
+ <div>
+ <button phx-click="update_page" phx-value-page="1" disabled={@page == 1}>先頭へ</button>
+ <button phx-click="update_page" phx-value-page={@page - 1} disabled={@page == 1}>前へ</button>
+ <button phx-click="update_page" phx-value-page={@page + 1} disabled={@page == @total_pages}>次へ</button>
+ <button phx-click="update_page" phx-value-page={@total_pages} disabled={@page == @total_pages}>最後尾へ</button>
+ </div>
+ </div>
+ """
+ end
ビューにコンポーネントを設置
Phoenix1.7に合わせてcore_components.ex
内に作った関数コンポーネントを呼び出しました。
+ <.paginator
+ total_entries={@users.total_entries}
+ page_size={@users.page_size}
+ page={@users.page_number}
+ total_pages={@users.total_pages}
+ >
+ </.paginator>
Contextを修正
元記事様そのままです。
def list_users() do
build_list_query()
|> Repo.paginate()
end
def list_users(page, page_size) do
build_list_query()
|> Repo.paginate(page: page, page_size: page_size)
end
defp build_list_query() do
from(u in User,
order_by: [desc: u.id]
)
end
LiveView側の記述を修正
ページが変更されたときに、ページサイズがリセットされないよう、すでにセット済みの値を考慮してリダイレクトしたいのですが、下記関数がLiveView v0.20.1では廃止されて使用できなかったので下記の通り変更しました。
・push_redirect -> push_navigateでクエリパラメータを渡すように変更
defmodule Nov11Web.UserLive.Index do
use Nov11Web, :live_view
alias Nov11.Users
alias Nov11.Users.User
@default_page 1
@default_page_size 5
@impl true
def mount(_params, _session, socket) do
{:ok, stream(socket, :users, Users.list_users())}
end
@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit User")
|> assign(:user, Users.get_user!(id))
end
defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New User")
|> assign(:user, %User{})
end
defp apply_action(socket, :index, params) do
socket
|> assign(:page_title, "Listing Users")
|> assign(:user, nil)
|> assign(:users, list_users(params))
end
@impl true
def handle_info({Nov11Web.UserLive.FormComponent, {:saved, user}}, socket) do
{:noreply, stream_insert(socket, :users, user)}
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
user = Users.get_user!(id)
{:ok, _} = Users.delete_user(user)
{:noreply, stream_delete(socket, :users, user)}
end
@impl true
def handle_event("update_page", %{"page" => page}, socket) do
- params =
- socket.assigns
- |> Map.get(:users)
- |> Map.take([:page_number, :page_size])
- |> Map.merge(%{page_number: page})
- |> Keyword.new()
+ page_size =
+ socket.assigns
+ |> Map.get(:users)
+ |> Map.take([:page_number, :page_size])
+ |> Map.merge(%{page_number: page})
+ |> Keyword.new()
+ |> Keyword.get(:page_size)
+ page_number =
+ socket.assigns
+ |> Map.get(:users)
+ |> Map.take([:page_number, :page_size])
+ |> Map.merge(%{page_number: page})
+ |> Keyword.new()
+ |> Keyword.get(:page_number)
- {:noreply,
- push_redirect(socket,
- to: Routes.user_index_path(socket, :index, params)
- )}
+ {:noreply,
+ push_navigate(socket, to: ~p"/users?page_number=#{page_number}&page_size=#{page_size}")}
+ end
@impl true
def handle_event("update_page_size", %{"page_size" => page_size}, socket) do
- params =
- socket.assigns
- |> Map.get(:users)
- |> Map.take([:page_number, :page_size])
- |> Map.merge(%{page_size: page_size})
- |> Keyword.new()
+ page_size =
+ socket.assigns
+ |> Map.get(:users)
+ |> Map.take([:page_number, :page_size])
+ |> Map.put(:page_size, page_size)
+ |> Map.get(:page_size)
+ page_number =
+ socket.assigns
+ |> Map.get(:users)
+ |> Map.take([:page_number, :page_size])
+ |> Map.get(:page_number)
- {:noreply,
- push_redirect(socket,
- to: Routes.user_index_path(socket, :index, params)
- )}
+ {:noreply,
+ push_navigate(socket, to: ~p"/users?page_number=#{page_number}&page_size=#{page_size}")}
+ end
defp list_users(%{"page_number" => page, "page_size" => page_size}) do
Users.list_users(page, page_size)
end
defp list_users(%{"page_number" => page}) do
Users.list_users(page, @default_page_size)
end
defp list_users(%{"page_size" => page_size}) do
Users.list_users(@default_page, page_size)
end
defp list_users(%{}) do
Users.list_users()
end
end
不明点(解決出来たら別記事化します)
・クエリパラメータは渡せたが画面上での更新がされません
→クエリパラメータを受け取る方法が分かっていません
下記検証の結果、list_users(page, page_size)
で%Scrivener.Page{}内のpage_numberとpage_sizeの値が更新されることが分かっています。
では、クエリパラメータをどうやって受け取って上記の変数page
, page_size
にそれぞれ当てはめる?...ここが分かっていない箇所です。
iex -S mix
iex(1)> Nov11.Users.list_users()
%Scrivener.Page{
page_number: 1,
page_size: 5,
total_entries: 23,
total_pages: 5,
entries: [
%Nov11.Users.User{
...
iex(2)> Nov11.Users.list_users(2, 3)
%Scrivener.Page{
page_number: 2,
page_size: 3,
total_entries: 23,
total_pages: 8,
entries: [
%Nov11.Users.User{
...
現時点で学んだこと
1.Scrivenerを導入すること自体はできました(画面側がダメなので追って理解を深めたいと思います)
2.Phoenix1.7.10/LiveView v0.20.1の環境ではpush_redirect
が廃止されており、リダイレクトの書き方が変わっているということを学びました。
~Elixirの国のご案内~
↓Elixirって何ぞや?と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます
↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ!私もエンジニア未経験から学習中です。
↓We Are The Alchemists, my friends!1
Elixirコミュニティは本当に優しくて温かい人たちばかり!
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。2
-
@torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。 ↩