Last active
June 23, 2023 23:36
-
-
Save jswanner/238e07fdf9a4c0374e437038d2b40f41 to your computer and use it in GitHub Desktop.
Single-file Phoenix LiveView application with user-selectable table columns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/[email protected]/priv/static/phoenix.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a full working Phoenix LiveView application. After downloading the file, start it as:
You can then view by going to http://localhost:4000