The fields of the inner form inputs_for got reset when modifying other fields

I have a map field which stores my mobile_json and I used inputs_for to display the embedded_schema’s fields which looks like:

<%= inputs_for f, :m_json, fn mobile_json -> %>
<div class="mobile-number-input-container">
  <div>
    <%= select mobile_json, :mcc, @country_dialing_codes %>
    <%= error_tag mobile_json, :mcc %>
  </div>
  <div>
    <%= number_input mobile_json, :mobile_nb, placeholder: "e.g. 90123456" %>
    <%= error_tag mobile_json, :mobile_nb %>
  </div>
</div>
<% end %>

This is what the form looks like:

Step 1: Fill in the one of the mobile_json fields

Step 2: Modify any other fields (e.g. Country)

As you can see the Mobile Number field reset back to empty. When you modify any other fields, the data in the inputs_for will be reset.

Really struggling to find solutions online, I really need help.

Thank you so so much in advance.

The changes to the m_json part of your changeset are maybe not begin persisted properly between handle_event calls.

Can you post the part of the code that’s setting the changesets and modifying them from params?

Hi @03juan,

Here is a snippet:

  # form_component.ex
  def update(%{user: %{id: _user_id} = user} = assigns, socket) do

    {
      :ok,
      socket
      # ...
      |> assign_changeset(assigns.action, user)
      # ...
  end

  defp assign_changeset(socket, action, user) when :edit === action,
    do: socket |> assign(:changeset, Accounts.new_user_changeset(user))

  defp assign_changeset(socket, action, user) when :index === action or :new === action,
    do: socket |> assign(:changeset, Accounts.update_user_changeset(user))
  # accounts.ex
  def new_user_changeset(%User{} = user, attrs \\ %{}) do
    user
    |> User.email_changeset(attrs)
    |> User.creation_changeset(attrs)
  end

  def update_user_changeset(%User{} = user, attrs \\ %{}) do
    user
    |> User.email_changeset(attrs)
    |> User.update_changeset(attrs)
  end

There’s something important missing from the call to new_user_changeset: the second parameter!

Note that LiveView will not overwrite the element you just edited, so it looks like only the last value you sent sticks around.

1 Like

Thank you so much for guiding me in the right direction!

my solution (just for anyone who hits it in the future):


defp assign_changeset(socket, :edit), do: # ...
defp assign_changeset(socket, _), do: # ...
defp assign_changeset(socket, :validate, attrs),
  do:
    socket
    |> assign(
      :changeset,
      Accounts.update_user_changeset(socket.assigns.user, attrs)
      |> Map.put(:action, :validate)
    )

# My validate of my form handle_event
@impl true
def handle_event("validate", %{"user" => user_params} = data, socket) do
  {:noreply, socket |> assign_changeset(:validate, user_params)}
end

Just like what @al2o3cr said, my mistake was that I did not pass my changed attribute into the changeset, that was why it was always reset back to what it was.