Skip to content

Instantly share code, notes, and snippets.

@jc00ke
Created April 8, 2019 20:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jc00ke/b8aa7812f6405fcb945ec4af4b60b63a to your computer and use it in GitHub Desktop.
Save jc00ke/b8aa7812f6405fcb945ec4af4b60b63a to your computer and use it in GitHub Desktop.
# from https://github.com/joerichsen/phoenix_live_view_example/blob/be9315feb30f377fb144b1b03b2f93f792bfbfa7/lib/demo_web/live/table_live.ex
defmodule DemoWeb.TableLive do
use Phoenix.LiveView
def render(assigns) do
~L"""
<form phx-change="search"><input type="text" name="query" value="<%= @query %>" placeholder="Search..." /></form>
<table>
<thead>
<tr>
<th phx-click="sort" phx-value="name">
Name <%= sort_order_icon("name", @sort_by, @sort_order) %>
</th>
<th phx-click="sort" phx-value="population">
Population <%= sort_order_icon("population", @sort_by, @sort_order) %>
</th>
<th phx-click="sort" phx-value="region">
Region <%= sort_order_icon("region", @sort_by, @sort_order) %>
</th>
</tr>
</thead>
<tbody>
<%= for row <- rows(assigns) do %>
<tr>
<td><%= row["name"] %></td>
<td><%= row["population"] %></td>
<td><%= row["region"] %></td>
</tr>
<% end %>
</tbody>
</table>
<nav class="float-left">
<%= for page <- (1..number_of_pages(assigns)) do %>
<%= if page == @page do %>
<strong><%= page %></strong>
<% else %>
<a href="#" phx-click="goto-page" phx-value=<%= page %>><%= page %></a>
<% end %>
<% end %>
</nav>
<form phx-change="change-page-size" class="float-right">
<select name="page_size">
<%= for page_size <- [5, 10, 25, 50] do %>
<option value="<%= page_size %>" <%= page_size == @page_size && "selected" || "" %>>
<%= page_size %> per page
</option>
<% end %>
</select>
</form>
"""
end
def mount(_session, socket) do
{:ok, assign(socket, data: Demo.Country.list(), query: nil, sort_by: "name", sort_order: :desc, page: 1, page_size: 10)}
end
def handle_event("search", %{"query" => query}, socket) do
{:noreply, assign(socket, query: query, page: 1)}
end
# When the column that is used for sorting is clicked again, we reverse the sort order
def handle_event("sort", column, %{assigns: %{sort_by: sort_by, sort_order: :asc}} = socket) when column == sort_by do
{:noreply, assign(socket, sort_by: sort_by, sort_order: :desc)}
end
def handle_event("sort", column, %{assigns: %{sort_by: sort_by, sort_order: :desc}} = socket) when column == sort_by do
{:noreply, assign(socket, sort_by: sort_by, sort_order: :asc)}
end
# A new column has been clicked
def handle_event("sort", column, socket) do
{:noreply, assign(socket, sort_by: column)}
end
def handle_event("goto-page", page, socket) do
{:noreply, assign(socket, page: String.to_integer(page))}
end
def handle_event("change-page-size", %{"page_size" => page_size}, socket) do
{:noreply, assign(socket, page_size: String.to_integer(page_size), page: 1)}
end
defp rows(%{data: data, query: query, sort_by: sort_by, sort_order: sort_order, page: page, page_size: page_size}) do
data |> filter(query) |> sort(sort_by, sort_order) |> paginate(page, page_size)
end
defp filter(rows, query) do
rows |> Enum.filter(&(String.match?(&1["name"], ~r/#{query}/i)))
end
defp sort(rows, sort_by, :asc), do: rows |> Enum.sort(&(&1[sort_by] > &2[sort_by]))
defp sort(rows, sort_by, :desc), do: rows |> Enum.sort(&(&1[sort_by] <= &2[sort_by]))
defp paginate(rows, page, page_size), do: rows |> Enum.slice((page - 1) * page_size, page_size)
defp number_of_pages(%{data: data, query: query, page_size: page_size}) do
number_of_rows = data |> filter(query) |> length
(number_of_rows / page_size) + 1 |> trunc
end
defp sort_order_icon(column, sort_by, :asc) when column == sort_by, do: "▲"
defp sort_order_icon(column, sort_by, :desc) when column == sort_by, do: "▼"
defp sort_order_icon(_, _, _), do: ""
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment