Listing Cats

Reset
NameColorOwnerCategory
Marley Black Brian Real

Allows for a shareable URL such as liveviewbasics.com/basic-eleven?q=ar&category=Real&sort_by=Color .

Documentation:

https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#c:handle_params/3

https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#push_patch/2

NOTE: reference the Setup section for generating the Animals context and adding the Cats to the database used in this example.

scope "/", LiveViewBasicsWeb do
  pipe_through :browser

  live "/cats", CatLive.Index, :index
end
defmodule LiveViewBasicsWeb.CatLive.Index do
  use LiveViewBasicsWeb, :live_view

  alias LiveViewBasics.Animals

  def mount(_params, _session, socket) do
    {:ok, socket}
  end

  def handle_params(params, _uri, socket) do
    socket =
      socket
      |> stream(:cats, Animals.filter_cats(params), reset: true)
      |> assign(:form, to_form(params))

    {:noreply, socket}
  end

  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash}>
      <.header>
        Listing Cats
      </.header>
      <div class="mb-2">
        <.form
          class="sm:flex justify-left gap-4 items-center"
          for={@form}
          id="filter-form"
          phx-change="filter"
          phx-submit="filter"
        >
          <.input field={@form[:q]} placeholder="Search..." autocomplete="off" phx-debounce="500" />

          <.input
            type="select"
            field={@form[:category]}
            prompt="Category"
            options={["Real", "Fictional"]}
          />

          <.input
            type="select"
            field={@form[:sort_by]}
            prompt="Sort By"
            options={["Name", "Color", "Owner"]}
          />

          <.link class="mb-2" patch={~p"/cats"}>
            Reset
          </.link>
        </.form>

        <.table id="cats" rows={@streams.cats}>
          <:col :let={{_id, cat}} label="Name">{cat.name}</:col>
          <:col :let={{_id, cat}} label="Color">{cat.color}</:col>
          <:col :let={{_id, cat}} label="Owner">{cat.owner}</:col>
          <:col :let={{_id, cat}} label="Category">{cat.category}</:col>
        </.table>
      </div>
    <Layouts.app flash={@flash}>
    """
  end

  def handle_event("filter", params, socket) do
    params =
      params
      |> Map.take(~w(q category sort_by))
      |> Map.reject(fn {_, v} -> v == "" end)

    socket = push_patch(socket, to: ~p"/cats?#{params}")

    {:noreply, socket}
  end
end
def filter_cats(filter) do
  Cat
  |> where([c], ilike(c.name, ^"%#{filter["q"]}%"))
  |> with_category(filter["category"])
  |> sort(filter["sort_by"])
  |> Repo.all()
end

defp with_category(query, category) when category in ~w(Real Fictional) do
  where(query, category: ^category)
end

defp with_category(query, _), do: query

defp sort(query, "Name"), do: order_by(query, :name)
defp sort(query, "Color"), do: order_by(query, :color)
defp sort(query, "Owner"), do: order_by(query, :owner)
defp sort(query, _), do: order_by(query, :id)