Conversation
|
Updated example from #4049: Application.put_env(:sample, Example.Endpoint,
adapter: Bandit.PhoenixAdapter,
http: [ip: {127, 0, 0, 1}, port: 5001],
server: true,
live_view: [signing_salt: "aaaaaaaa"],
secret_key_base: String.duplicate("a", 64)
)
Mix.install([
{:bandit, "~> 1.0"},
{:jason, "~> 1.0"},
{:phoenix, "~> 1.8.0"},
{:phoenix_live_view, github: "phoenixframework/phoenix_live_view", branch: "sd-phx-track-attributes-assets", override: true},
# {:phoenix_live_view, path: "~/oss/phoenix_live_view", override: true},
])
defmodule Example.ErrorView do
def render(template, _), do: Phoenix.Controller.status_message_from_template(template)
end
defmodule Example.HomeLive do
use Phoenix.LiveView, layout: {__MODULE__, :live}
alias Phoenix.LiveView.JS
def mount(_params, _session, socket) do
{:ok, assign(socket, count: 0, serverval: "serverval")}
end
defp phx_vsn, do: Application.spec(:phoenix, :vsn)
defp lv_vsn, do: Application.spec(:phoenix_live_view, :vsn)
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>
<script>
let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket)
liveSocket.connect()
document.addEventListener("show", () => {
document.getElementById("abc").removeAttribute("hidden")
})
document.addEventListener("show+ignore", () => {
let el = document.getElementById("abc")
liveSocket.js().ignoreAttributes(el, ["hidden"])
el.removeAttribute("hidden")
})
document.addEventListener("clientattr", (e) => {
e.target.setAttribute("data-test", "clientval");
});
</script>
<style>
* { font-size: 1.1em; }
</style>
{@inner_content}
"""
end
def render(assigns) do
~H"""
<div id="abc" hidden phx-track-attributes>{@count}</div>
<button phx-click={JS.dispatch("show")}>Show dispatch</button>
<button phx-click={JS.remove_attribute("hidden", to: "#abc")}>Show JS cmd</button>
<button phx-click={JS.dispatch("show+ignore")}>Show dispatch + ignore</button>
<button phx-click={JS.dispatch("clientattr")} data-test={@serverval} phx-track-attributes>Set attribute</button>
<br />
<button phx-click="inc">+</button>
<button phx-click="dec">-</button>
<button phx-click="set-server">Set attribute from server</button>
"""
end
def handle_event("inc", _params, socket) do
{:noreply, assign(socket, :count, socket.assigns.count + 1)}
end
def handle_event("dec", _params, socket) do
{:noreply, assign(socket, :count, socket.assigns.count - 1)}
end
def handle_event("set-server", _params, socket) do
{:noreply, assign(socket, :serverval, "Foo #{System.unique_integer()}")}
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) |
|
As usual as long is well documented I think it's a nice direction. This would reduce complexity of Hooks for sure. Specially for component library authors. |
|
Yeah I'm not sure yet how useful this is in practice. I tried to use this together with the Tailwind Elements web components, but they still won't work because they also rely on ID fields being set by the library, which conflicts with morphdom. Setting static IDs breaks the Tailwind modal... So: this is mostly a proof of concept to validate that it works, but at the moment I'm leaning to not actually merge it (unless someone has good arguments for it!). |
|
Update: making Tailwind Elements work was actually quite easy - we just need to ensure the node key uses the original element copy. |
Adds `phx-update="track-attributes` and `phx-track-attributes` attribute where the first one tracks attributes on the whole subtree and the second one only for the element that set the attribute. Using this makes LiveView keep clientside changes until a server overrides an attribute value with a new one. This is useful when clientside libraries rely on attributes they set, but `phx-update="ignore"` is too much. This is a proof of concept, I'm not sure we actually want to go with this. For simplicitly, I vendored morphdom into the repo. The important change there is a new `proxyFromEl` callback + changes to morphAttrs. Relates to: #4049 Relates to: #4050 (comment)
c28f29d to
58c8704
Compare
Adds
phx-update="track-attributesandphx-track-attributesattribute where the first one tracks attributes on the whole subtree and the second one only for the element that set the attribute.Using this makes LiveView keep clientside changes until a server overrides an attribute value with a new one. This is useful when clientside libraries rely on attributes they set, but
phx-update="ignore"is too much.This is a proof of concept, I'm not sure we actually want to go with this. For simplicitly, I vendored morphdom into the repo. The important change there is a new
proxyFromElcallback + changes to morphAttrs.Relates to: #4049
Relates to: #4050 (comment)