How to properly reset a forms changeset

I have a simple form setup using form_for/3:

<%= f = form_for @post_changeset, "#", phx_change: "validate", phx_submit: "save" %>
  <%= label f, :headline %>
  <%= text_input f, :headline %>
  <%= error_tag f, :headline %>
  <%= label f, :content %>
  <%= text_input f, :content %>
  <%= error_tag f, :content %>
  <%= label f, :pinned %>
  <%= checkbox f, :pinned %>
  <%= error_tag f, :pinned %>
  <%= submit "Save", phx_disable_with: "Saving..." %>

This form is appending posts to its parent (a ‘project’) using this submit handler:

  def handle_event("save", %{"post" => post_params}, socket) do
    case Projects.create_post(socket.assigns.project, post_params) do
      {:ok, post} ->

         |> put_flash(:info, "Post created successfully")
         |> assign(:project, %{
           | posts: socket.assigns.project.posts ++ [post]
         |> assign(:post, %Projects.Post{})
         |> assign(:post_changeset, Projects.change_post(%Projects.Post{}, socket.assigns.project))}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, post_changeset: changeset)}

What it should do:
After the submit, the newly created post should be appended to the existing posts (without reloading/recreating the liveview). The form should be reset, meaning the inputs are empty and the form is ‘pristine’ again (not dirty/touched).

What it’s currently doing:
After the submit, the newly created post is appended to the existing posts (without a reload). The form inputs are cleared but after tabbing from the first input (after typing something into it) to the second (e.g. headline → content), the changeset error for that field is instantly displayed even though the input hasn’t been dirtied. I would expect that the form behaves like on a fresh page render.

What am I missing?

Welcome @rsmidt!

Your example looks pretty straightforward, but if there is an issue with the changeset after save it is likely coming from here:

If you inspect this changeset before assigning it to the socket, does it contain any errors?

You may also want to look at the docs for phx-feedback-for for more information on how you can hide error tags for unchanged form fields.

Hi @mcrumm,

Thank you very much for your answer!

The docs for phx-feedback-for state:

Now, any DOM container with the phx-feedback-for attribute will receive a phx-no-feedback class in cases where the form fields has yet to receive user input/focus.

Maybe because the form had focus/received user input before the submit that state is not reset after the submit? Maybe the form needs to be reset completely to make it think there was no previous user interaction? How would I do that?

I’m new to both phoenix and phoenix liveview, maybe I’m not thinking in Phoenix terms yet.

The touched/submitted state for the form and its inputs is automatically reset by LiveView after the submit, so there is nothing you need to do to reset it.

It is difficult to determine the exact problem without seeing a full example. If you can can create a small example app that reproduces the problem I would be happy to take a closer look.

If you can can create a small example app that reproduces the problem I would be happy to take a closer look.

Thank you very much! Is there a better way to provide a full example other than creating a git repo? :slight_smile:

A git repo would be a great way to share a full example, right now I can’t think of a better one :slight_smile: