Skip to content

Instantly share code, notes, and snippets.

@jswanner
Last active June 23, 2023 23:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jswanner/238e07fdf9a4c0374e437038d2b40f41 to your computer and use it in GitHub Desktop.
Save jswanner/238e07fdf9a4c0374e437038d2b40f41 to your computer and use it in GitHub Desktop.
Single-file Phoenix LiveView application with user-selectable table columns
signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode16()
secret_base = :crypto.strong_rand_bytes(32) |> Base.encode16()
Application.put_env(:phoenix, :json_library, Jason)
Application.put_env(:sample, SamplePhoenix.Endpoint,
adapter: Bandit.PhoenixAdapter,
http: [
ip: {127, 0, 0, 1},
port: String.to_integer(System.get_env("PORT") || "4000")
],
live_view: [signing_salt: signing_salt],
secret_key_base: secret_base,
server: true,
url: [host: "localhost"]
)
Mix.install([
{:bandit, "~> 0.7.7"},
{:ecto, "~> 3.10.2"},
{:jason, "~> 1.0"},
{:phoenix, "~> 1.7.6"},
{:phoenix_live_view, "~> 0.19.3"},
{:phoenix_view, "~> 2.0.2"}
])
defmodule SamplePhoenix.Person do
defstruct [:address, :email, :id, :name]
end
defmodule SamplePhoenix.ErrorView do
use Phoenix.View, root: ""
def render(_, _), do: "error"
end
defmodule SamplePhoenix.SampleLive do
use Phoenix.LiveView, container: {:html, []}, layout: {__MODULE__, :layout}
defp column_header(schema, column), do: Ecto.Enum.mappings(schema, :columns)[column]
defp column_value(person, column), do: Map.get(person, column)
def handle_event("update-columns", params, socket) do
current_columns =
{%{}, socket.assigns.schema}
|> Ecto.Changeset.cast(params, [:columns])
|> Ecto.Changeset.apply_changes()
|> Map.get(:columns, [])
{:noreply, assign(socket, :current_columns, current_columns)}
end
def mount(_params, _session, socket) do
people = for n <- 1..20 do
%SamplePhoenix.Person{
address: "#{n} Main St",
email: "email-#{n}@example.com",
id: n,
name: "Name #{n}"
}
end
schema = %{
columns:
{:array,
Ecto.ParameterizedType.init(Ecto.Enum,
values: [id: "ID", name: "Name", email: "Email", address: "Address"]
)}
}
socket =
socket
|> assign(:current_columns, Ecto.Enum.values(schema, :columns))
|> assign(:people, people)
|> assign(:schema, schema)
{:ok, socket}
end
def render("layout.html", assigns) do
~H"""
<head>
<script src="https://cdn.jsdelivr.net/npm/phoenix@1.7.6/priv/static/phoenix.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/phoenix_live_view@0.19.3/priv/static/phoenix_live_view.min.js"></script>
<script>
let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket)
liveSocket.connect()
</script>
<style>
* { font-size: 1.1em; }
</style>
</head>
<body>
<%= @inner_content %>
</body>
"""
end
def render(assigns) do
~H"""
<form phx-change="update-columns">
<label :for={{value, label} <- Ecto.Enum.mappings(@schema, :columns)}>
<input
checked={value in @current_columns}
name="columns[]"
type="checkbox"
value={value}
/>
<%= label %>
</label>
</form>
<table>
<thead>
<tr>
<th :for={column <- @current_columns}><%= column_header(@schema, column) %></th>
</tr>
</thead>
<tbody>
<tr :for={person <- @people}>
<td :for={column <- @current_columns}><%= column_value(person, column) %></td>
</tr>
</tbody>
</table>
"""
end
end
defmodule Router do
use Phoenix.Router
import Phoenix.LiveView.Router
pipeline :browser do
plug :accepts, ["html"]
end
scope "/", SamplePhoenix do
pipe_through :browser
live "/", SampleLive, :index
end
end
defmodule SamplePhoenix.Endpoint do
use Phoenix.Endpoint, otp_app: :sample
socket "/live", Phoenix.LiveView.Socket
plug Router
end
{:ok, _} = Supervisor.start_link([SamplePhoenix.Endpoint], strategy: :one_for_one)
Process.sleep(:infinity)
@jswanner
Copy link
Author

This is a full working Phoenix LiveView application. After downloading the file, start it as:

elixir phx-liveview-single-file-filter-columns.exs

You can then view by going to http://localhost:4000

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment