HawkExDashboard.PaginatedSearch (hawk_ex_dashboard v0.1.0)

Copy Markdown View Source

Shared pagination + search behavior for LiveViews using the HawkExDashboard.Table component with URL-backed page/search state.

Usage

defmodule MyLive do
  use Phoenix.LiveView
  use HawkExDashboard.PaginatedSearch, path: "/hawk_ex"

  @impl true
  def mount(_params, _session, socket) do
    {:ok,
     socket
     |> assign(:total_pages, 1)
     |> assign(:total_count, 0)
     |> assign(:loading, true)
     |> assign(:error, nil)
     |> stream(:my_rows, [])}
  end

  @impl true
  def handle_params(params, _uri, socket) do
    {:noreply, paginated_search_params(socket, params, &load_data/3)}
  end

  defp load_data(socket, page, search) do
    start_async(socket, :load_recent, fn ->
      MyContext.list(page: page, per_page: 20, search: search)
    end)
  end

  @impl true
  def handle_async(:load_recent, {:ok, page_result}, socket) do
    handle_paginated_result(socket, page_result, fn socket, result ->
      socket
      |> assign(:total_pages, result.total_pages)
      |> assign(:total_count, result.total_count)
      |> stream(:my_rows, result.entries, reset: true)
    end)
  end

  def handle_async(:load_recent, {:exit, reason}, socket) do
    {:noreply, assign(socket, error: "...", loading: false)}
  end
end

This injects:

  • handle_event("table_page", ...)
  • handle_event("table_search", ...)
  • handle_event("table_retry", ...) — requires the using module to define load_data/3 (called as load_data(socket, page, search))
  • Helper functions: paginated_search_params/3, handle_paginated_result/4

Summary

Functions

Builds an Ecto-compatible order_by keyword from the socket's current sort assigns. Returns [desc: :inserted_at] as default.

Call from the success branch of handle_async/3. Given the loaded page_result (must have :page and :total_pages keys), either redirects to the last valid page if the requested page no longer exists (e.g. search narrowed results), or calls assign_fun.(socket, result) to apply the real data to assigns.

Call from handle_params/3. Parses page/search from URL params, assigns them, and calls the given load_fun.(socket, page, search) to kick off data loading (typically an async load).

Functions

current_order_by(socket)

Builds an Ecto-compatible order_by keyword from the socket's current sort assigns. Returns [desc: :inserted_at] as default.

Use inside load_data/3 to avoid repeating this pattern in every LiveView:

defp load_data(socket, page, search) do
  start_async(socket, :load_recent, fn ->
    MyContext.list(
      page: page,
      per_page: 20,
      search: search,
      order_by: current_order_by(socket)
    )
  end)
end

handle_paginated_result(socket, base_path, page_result, assign_fun)

Call from the success branch of handle_async/3. Given the loaded page_result (must have :page and :total_pages keys), either redirects to the last valid page if the requested page no longer exists (e.g. search narrowed results), or calls assign_fun.(socket, result) to apply the real data to assigns.

paginated_search_params(socket, params, load_fun, opts \\ [])

Call from handle_params/3. Parses page/search from URL params, assigns them, and calls the given load_fun.(socket, page, search) to kick off data loading (typically an async load).

parse_dir(arg1)