Created
May 2, 2025 07:40
-
-
Save ftes/71071ae0c478a0d26e25c89fbbc7b564 to your computer and use it in GitHub Desktop.
Single file phoenix example: .heex global attribute overrides
This file contains hidden or 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
Application.put_env(:sample, Example.Endpoint, | |
http: [ip: {127, 0, 0, 1}, port: 5001], | |
server: true, | |
live_view: [signing_salt: "aaaaaaaa"], | |
secret_key_base: String.duplicate("a", 64) | |
) | |
Mix.install( | |
[ | |
{:plug_cowboy, "~> 2.5"}, | |
{:jason, "~> 1.0"}, | |
{:phoenix, "~> 1.7"}, | |
# please test your issue using the latest version of LV from GitHub! | |
{:phoenix_live_view, | |
github: "phoenixframework/phoenix_live_view", branch: "main", override: true} | |
] | |
) | |
# if you're trying to test a specific LV commit, it may be necessary to manually build | |
# the JS assets. To do this, uncomment the following lines: | |
# this needs mix and npm available in your path! | |
# | |
# path = Phoenix.LiveView.__info__(:compile)[:source] |> Path.dirname() |> Path.join("../") | |
# System.cmd("mix", ["deps.get"], cd: path, into: IO.binstream()) | |
# System.cmd("npm", ["install"], cd: Path.join(path, "./assets"), into: IO.binstream()) | |
# System.cmd("mix", ["assets.build"], cd: path, into: IO.binstream()) | |
defmodule Example.ErrorView do | |
def render(template, _), do: Phoenix.Controller.status_message_from_template(template) | |
end | |
defmodule Example.Components do | |
use Phoenix.Component | |
attr :expected, :string | |
attr :"phx-debounce", :string, default: "blur" | |
def dedicated_attr_with_default(assigns) do | |
~H""" | |
<input | |
phx-debounce={assigns[:"phx-debounce"]} | |
data-expected={@expected} | |
/> | |
""" | |
end | |
attr :expected, :string | |
attr :rest, :global | |
def before_rest_naive(assigns) do | |
~H""" | |
<input | |
phx-debounce="blur" | |
{@rest} | |
data-expected={@expected} | |
/> | |
""" | |
end | |
attr :expected, :string | |
attr :rest, :global | |
def after_rest_naive(assigns) do | |
~H""" | |
<input | |
{@rest} | |
phx-debounce="blur" | |
data-expected={@expected} | |
/> | |
""" | |
end | |
attr :expected, :string | |
attr :rest, :global | |
def before_rest_conditional(assigns) do | |
~H""" | |
<input | |
phx-debounce={if not Map.has_key?(@rest, :"phx-debounce"), do: "blur"} | |
{@rest} | |
data-expected={@expected} | |
/> | |
""" | |
end | |
attr :expected, :string | |
attr :rest, :global | |
def after_rest_conditional(assigns) do | |
~H""" | |
<input | |
{@rest} | |
phx-debounce={if not Map.has_key?(@rest, :"phx-debounce"), do: "blur"} | |
data-expected={@expected} | |
/> | |
""" | |
end | |
end | |
defmodule Example.HomeLive do | |
use Phoenix.LiveView, layout: {__MODULE__, :live} | |
def mount(_params, _session, socket) do | |
{:ok, assign(socket, :count, 0)} | |
end | |
def render("live.html", assigns) do | |
~H""" | |
<script src="/assets/phoenix/phoenix.js"> | |
</script> | |
<script src="/assets/phoenix_live_view/phoenix_live_view.js"> | |
</script> | |
<%!-- uncomment to use enable tailwind --%> | |
<%!-- <script src="https://cdn.tailwindcss.com"></script> --%> | |
<script> | |
let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket) | |
liveSocket.connect() | |
</script> | |
<style> | |
* { font-size: 16px; } | |
</style> | |
{@inner_content} | |
""" | |
end | |
def render(assigns) do | |
~H""" | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
document.querySelectorAll('input').forEach(input => { | |
const value = input.getAttribute('phx-debounce') | |
const expected = input.getAttribute('data-expected') | |
console.log(value, expected) | |
input.outerHTML += `<br/>${value == expected && "✅" || "❌"} phx-debouce = ${value}` | |
}) | |
}) | |
</script> | |
<table id="table" phx-update="ignore"> | |
<tr> | |
<th></th> | |
<th>No override</th> | |
<th>Override phx-debouce="100"</th> | |
<th>Override phx-debouce="nil"</th> | |
</tr> | |
<tr> | |
<td>Dedicated attr with default</td> | |
<td><Example.Components.dedicated_attr_with_default expected="blur" /></td> | |
<td><Example.Components.dedicated_attr_with_default phx-debounce="100" expected="100" /></td> | |
<td><Example.Components.dedicated_attr_with_default phx-debounce={nil} expected={nil} /></td> | |
</tr> | |
<tr> | |
<td>Default before @rest naive</td> | |
<td><Example.Components.before_rest_naive expected="blur" /></td> | |
<td><Example.Components.before_rest_naive phx-debounce="100" expected="100" /></td> | |
<td><Example.Components.before_rest_naive phx-debounce={nil} expected={nil} /></td> | |
</tr> | |
<tr> | |
<td>Default after @rest naive</td> | |
<td><Example.Components.before_rest_naive expected="blur" /></td> | |
<td><Example.Components.after_rest_naive phx-debounce="100" expected="100" /></td> | |
<td><Example.Components.after_rest_naive phx-debounce={nil} expected={nil} /></td> | |
</tr> | |
<tr> | |
<td>Default before @rest conditional</td> | |
<td><Example.Components.before_rest_conditional expected="blur"/></td> | |
<td><Example.Components.before_rest_conditional phx-debounce="100" expected="100" /></td> | |
<td><Example.Components.before_rest_conditional phx-debounce={nil} expected={nil} /></td> | |
</tr> | |
<tr> | |
<td>Default after @rest conditional</td> | |
<td><Example.Components.before_rest_conditional expected="blur" /></td> | |
<td><Example.Components.after_rest_conditional phx-debounce="100" expected="100" /></td> | |
<td><Example.Components.after_rest_conditional phx-debounce={nil} expected={nil} /></td> | |
</tr> | |
</table> | |
""" | |
end | |
end | |
defmodule Example.Router do | |
use Phoenix.Router | |
import Phoenix.LiveView.Router | |
pipeline :browser do | |
plug(:accepts, ["html"]) | |
end | |
scope "/", Example do | |
pipe_through(:browser) | |
live("/", HomeLive, :index) | |
end | |
end | |
defmodule Example.Endpoint do | |
use Phoenix.Endpoint, otp_app: :sample | |
socket("/live", Phoenix.LiveView.Socket) | |
plug Plug.Static, from: {:phoenix, "priv/static"}, at: "/assets/phoenix" | |
plug Plug.Static, from: {:phoenix_live_view, "priv/static"}, at: "/assets/phoenix_live_view" | |
plug(Example.Router) | |
end | |
{:ok, _} = Supervisor.start_link([Example.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