Created
August 15, 2023 12:12
-
-
Save dvic/9cd697a7364819938fb05e9713e1ee12 to your computer and use it in GitHub Desktop.
LiveView access form change tracking bug
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
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.7"}, | |
{:phoenix_live_view, "~> 0.19.5"} | |
]) | |
defmodule Example.ErrorView do | |
def render(template, _), do: Phoenix.Controller.status_message_from_template(template) | |
end | |
defmodule Items do | |
end | |
defmodule Example.HomeLive do | |
use Phoenix.LiveView, layout: {__MODULE__, :live} | |
def mount(_params, _session, socket) do | |
items = %{ | |
"foo" => "foo", | |
"extras" => %{} | |
} | |
{:ok, assign(socket, items: items, form: to_form(items))} | |
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={"https://cdn.jsdelivr.net/npm/phoenix@#{phx_vsn()}/priv/static/phoenix.min.js"}></script> | |
<script src={"https://cdn.jsdelivr.net/npm/phoenix_live_view@#{lv_vsn()}/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> | |
<%= @inner_content %> | |
""" | |
end | |
def render(assigns) do | |
~H""" | |
<div>working: <.item item={Access.get(@form, :foo)} /></div> | |
<div>not working: <.item item={@form[:foo]} /></div> | |
<button phx-click="change_item">change</button> | |
""" | |
end | |
def item(assigns) do | |
form = assigns.item.form | |
assigns = assign(assigns, value: assigns.item.value <> (form.source["extras"]["foo"] || "")) | |
~H""" | |
<span><%= @value %></span> | |
""" | |
end | |
def handle_event("change_item", _params, socket) do | |
# update the source of the form | |
socket = | |
update(socket, :items, fn items -> | |
update_in(items["extras"], fn | |
%{"foo" => extra} = extras -> %{extras | "foo" => extra <> "!"} | |
%{} = extras -> Map.put(extras, "foo", "!") | |
end) | |
end) | |
# recreate the form | |
socket = assign(socket, :form, to_form(socket.assigns.items)) | |
{:noreply, socket} | |
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(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