ammancilla
LiveView form auto-recovery not working when form is rendered through a Live Component
TLDR; A recoverable form rendered through a Live Component doesn’t recover after crashes or disconnects.
DETAILS
Specifications
- Phoenix
1.7.14 - LiveView
0.20.17&&1.0.0-rc.7
Context
A form is being rendered through a Live Component. It fulfills the requirements to be recoverable after crashes and disconnects, as per Form bindings — Phoenix LiveView v1.2.5
- Has an
ID. - Is marked with
phx-change.
all forms marked with
phx-changeand havingidattribute will recover input values automatically after the user has reconnected or the LiveView has remounted after a crash.
Expected Behaviour
- After the live view crashes or disconnects, the form rendered through the Live Component is recovered.
Current Behavious
- After the live view crashes or disconnects, the from rendered through the Live Component is not recovered.
| on Crash | on Disconnect | |
|---|---|---|
![]() |
— | ![]() |
Steps to reproduce
- Clone https://github.com/ammancilla/phoenix_live_view_unrecoverable_form
mix phx.serverhttp://localhost:4000/form
or
- The Live View and respective Live Component
defmodule FormRecoverableWeb.FormLive do
@moduledoc false
use FormRecoverableWeb, :live_view
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :form, to_form(%{"name" => nil}))}
end
@impl true
def handle_event("validate", params, socket) do
{:noreply, assign(socket, :form, to_form(params))}
end
def handle_event("submit", _params, socket), do: raise("break live view")
@impl true
def render(assigns) do
~H"""
<div class="mx-auto flex justify-between prose">
<div>
<h2>The Form</h2>
<.simple_form id="person-form" for={@form} phx-change="validate" phx-submit="submit">
<.input field={@form[:name]} label="name" />
<:actions>
<.button phx-disable-with="Saving...">Crash LiveView</.button>
</:actions>
</.simple_form>
</div>
<div>
<h2>The Form from a Live Component</h2>
<.live_component
id="form-live-component"
form={@form}
module={AnnaBailaWeb.FormLiveComponent}
/>
</div>
</div>
"""
end
end
defmodule FormRecoverableWeb.FormLiveComponent do
@moduledoc false
use FormRecoverableWeb, :live_component
@impl true
def update(_assigns, socket) do
{:ok, assign(socket, :form, to_form(%{"username" => nil}))}
end
@impl true
def handle_event("validate", params, socket) do
{:noreply, assign(socket, :form, to_form(params))}
end
def handle_event("submit", _params, socket), do: raise("break live component")
@impl true
def render(assigns) do
~H"""
<div>
<.simple_form
id={"#{System.unique_integer()}"}
for={@form}
phx-submit="submit"
phx-target={@myself}
phx-change="validate"
>
<.input id="name-live-component" field={@form[:name]} label="name" />
<:actions>
<.button phx-disable-with="Saving...">Crash LiveComponent</.button>
</:actions>
</.simple_form>
</div>
"""
end
end
- What am I doing wrong?
- Is this expected behaviour or a bug?
Marked As Solved
Also Liked
joelpaulkoch
Hello
, can’t try it right now, but don’t you need to use the same id for the form in the live component? You will end up with a different id when you render the live component after the crash, no?
id={"#{System.unique_integer()}"}
benwilson512
You should still be generating distinct ids for each logical form in the assigns and then using that assign in the template. You’re going to get super weird behavior doing an impure call like that in the render itself, which is supposed to be deterministic from the assigns.
I can’t comment on the error you’re getting with a hard coded value, but I would definitely chase down that error and not go with an impure render, which is explicitly called out as a bad idea in the docs.
dimitarvp
Upload it to YouTube and post link?
Whoops, I commented literally seconds after you edited your second comment.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance











