poipoi
Form in Live components disappear after socket update
Hi, I am facing a problem I am unable to resolve.
In my socket assigns I have a list of evenings (structs).
For every evening in the list, I render a live component that contains a form relative to that evening.
There is also a button that adds an evening to the database and assigns the updated list of evenings to the socket.
When the page is first rendered, I can see every form without problem.
When I click the button to add an evening, the last form in the list “disappears”: all the input tags are removed from the html and the labels are emptied.
If I refresh the page, I can see everything.
I wrote a test to resolve this, but it always passes, and if I inspect the page with open_browser everything is ok.
I cannot understand what’s happening here, any help is appreciated.
I am using Phoenix 1.7.11 and LiveView 0.20.2
Marked As Solved
LostKobrakai
Looking at the docs it seems there’s even a separate option for id prefix vs name prefix: Phoenix.Component — Phoenix LiveView v1.0.0-rc.7
You’d need to use a unique prefix per student form you render, where the prefix will be applied to all inputs related to the form.
In your example codebase it could be something like this:
defp assign_form(socket) do
changeset = Students.change_student(socket.assigns.student)
socket |> assign(:form, to_form(changeset, id: "student_#{socket.assigns.student.id}"))
end
Also Liked
LostKobrakai
The better way to handle this would be to use to_form(data, id: unique_prefix), which would make the id generation be unique without messing with components.
_io2
Try checking the id of each rendered forms is unique. It sounds like the handle_event when an action is performed on one of the forms clears out the others.
If that doesn’t help, show your form rendering code and you might be able to get better help.
joshamb
It’s essentially because the input’s share the same id, across the forms.
The TLDR is that this is a HTML naughty and LV doesn’t know which input has been updated so it wipes the others.
To ‘resolve’ your problem, ensure your input in core_components.ex has a unique id (it uses the name to work out the field on the form, so you don’t want to fiddle with that)
There is probably a better way of generating a unique ID, but below I have attached an example.
def input(assigns) do
~H"""
<div phx-feedback-for={@name}>
<.label for={@id}><%= @label %></.label>
<input
type={@type}
name={@name}
id={"#{@id}-#{Ecto.UUID.generate()}"} # THIS!!!!
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
class={[
"mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6",
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400",
@errors == [] && "border-zinc-300 focus:border-zinc-400",
@errors != [] && "border-rose-400 focus:border-rose-400"
]}
{@rest}
/>
<.error :for={msg <- @errors}><%= msg %></.error>
</div>
"""
end
Last Post!
poipoi
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
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









