This must be something minor, but I can’t seem to put my finger on it. Why are the values of the <.form>
not reset on a successful phx-submit
?
defmodule AppWeb.SomePageLive
def render(assigns) do
~H"""
<.live_component
id="some-id"
module={AppWeb.PostingBarComponent}
topic={@selected_topic}
user={@current_user}
/>
"""
end
end
defmodule AppWeb.PostingBarComponent
use Phoenix.LiveComponent
use AppWeb, :html
import Phoenix.HTML.Form
def mount(socket) do
{:ok, assign(socket,
post_draft: to_form(empty_changeset())
)}
end
def render(assigns) do
~H"""
<div>
<.form
for={@post_draft}
id="form-id"
phx-submit="submit_post"
phx-target={@myself}
>
<%= textarea(@post_draft, :content,
id: "post-input",
rows: 1,
placeholder: "Post to ##{@topic.name}"
) %>
<button type="submit">Submit</button>
</.form>
</div>
"""
end
def handle_event("submit_post", %{"post" => post}, %{assigns: assigns} = socket) do
%{topic: topic, user: user} = assigns
%{"content" => content} = post
case App.Social.create_post(content, topic.id, user.id) do
{:ok, _} ->
{:noreply, assign(socket,
post_draft: to_form(empty_changeset())
)}
{:error, changeset} ->
{:noreply, assign(socket, post_draft: to_form(changeset))}
end
end
defp empty_changeset() do
%App.Social.Post{}
|> Ecto.Changeset.change()
end
end
Is seems like {:noreply, assign(socket, post_draft: to_form(empty_changeset()))}
, after a successful submit, is not triggering the expected component rerender.
Away from computer, so can’t check, but I guess it could be the fact that the value of th assign post_draft
on mount and after submit are the same. Both are an empty changeset.
I could update the form assign on phx-change
in addition to phx-submit
, but that seems suboptimal, since I am only interested in the value of the form input directly after the submit event.
Or are you supposed to use phx-change
? Be it, with or without debouncing?
I ran into this problem the other day. The only good solution I found was to use phx-change
as you suggested. Another thing that worked was assigning a random ID – to_form(id: my_random_id)
– to the form but that feels like a hack.
2 Likes
Ha, I’ve been silently coming back to this thread and couldn’t for the life of me figure out what the problem was (I didn’t actually try and reproducing it locally, of course).
I always add id
s to forms for testing purposes so that explains why I’ve never run into it. For that reason I don’t find it particularly hacky—Since LiveView is all about id
s, I’ve switched away from patterns like data-test-id
to a having a convention around plain ol’ html ids which reduces a lot of noise.
I’ve been in thinking about that recently: using ids instead of data attributes for testing. Not committed to it yet, but indeed LiveView does rely a lot on ids already.
I opted for adding a private function that randomizes the ids, thanks.
defp to_unique_form(changeset) do
to_form(changeset, id: "form-#{System.unique_integer()}")
end
defp empty_changeset() do
%App.Social.Post{}
|> Ecto.Changeset.change()
end
You definitely do not want to do this as it could have unintended consequences on change tracking. I had this idea before and was swiftly reminded that this was the case!
1 Like
Oh boy. Back to the keyboard
.
Since you have a live component for which you must provide an id already, you can get a unique form id with: id=“#{@component_id}-form}”
! I’m sure some people would scoff at the redundant “form” token in their id, but I personally don’t care about that stuff and this is exactly what I do.
I thought the idea of using the form id was to nudge LiveView into rerendering the form when the form data alone does not trigger a rerender, by using a different form id on each submit. Interestingly enough all my tests pass, when I use random ids. 
If I just set an id with to_form(id: "some_id")
, my form is not reset.
Also, I actually have little insight into how large the costs are of using phx-change="some_event"
on a form, in addition to phx-submit
. I catch myself assuming that the costs are relevant/not negligible.
It should be OK since you’re only setting the ID on mount and the submit event. I also used a Hook to reset the field before I went back to the phx-change because the Hook felt like duct tape instead of a real solution.
I’m curious about the costs with using phx-change because I’m using it a lot on a new project 
I realized I completely read past the meaning of “random” in your original reply so sorry if my replies sounded inconsistent (I figured you meant a random hardcoded ID).
It still seems a bit cavalier to use a totally random one but maybe it’s fine if it’s just the form? I’m trying to think of a scenario where the form would re-render and the ID would change. But ya… I can’t atm.
1 Like