Phoenix liveview form component event triggers the form's submit event

Hello all,

I have a liveview form component that has couple events that trigger to add associated changesets to a has_many relationship (with the hope that I’d later cast it along with the form changeset when I submit the form). The form has a builder for the associated entries so I’d expect this to work.

The issue is, when I trigger the add-entry event with a button click (not the save button), the form’s submit action is triggered and I can’t figure out why. Here’s some of my code … maybe you can help spot what I’m doing wrong:

<div>
  <.form
    let={f}
    for={@changeset}
    id="transaction-form"
    phx-target={@myself}
    phx-change="validate"
    phx-submit="save">

  <div class="form-group row">
      <%= for event_form <- inputs_for(f, :event) do %>
          <%= hidden_inputs_for(event_form) %>
          <%= hidden_input(event_form, :event_datetime, value: @params["event_date"] || nil) %>
          <div class="col-lg">
              <%= textarea event_form, :statement,
                  class: "form-control #{error_tag_class(event_form, :statement)}" %>
          </div>
      <% end %>
  </div>

                              <button class="btn btn-primary btn-small"
                                    phx-click="add-entry"
                                    phx-value-operation="op"
                                    phx-target={@myself}>add entry</button>

                      <%= for entry_form <- Enum.filter(inputs_for(f, :entries), &(input_value(&1, :operation) == "op")) do %>
                          <div class="form-group row" >
                              <%= hidden_inputs_for(entry_form) %>
                              <%= hidden_input(entry_form, :operation) %>
				<tr class="font-weight-boldest font-size-lg">
                                  <td class="col-3">
                                      <%= text_input(entry_form, :amount, class: "form-control") %>
                                  </td>
                              </tr>
                          </div>
                      <% end %>


  <div>
      <%= submit "save", phx_disable_with: "saving ...", class: "btn btn-primary mr-2" %>
  </div>
  </.form>
</div>

The form component counterpart is this:

defmodule MyAppWeb.App1Live.FormComponent do
  use MyAppWeb, :live_component

  @impl true
  def update(assigns, socket) do
    changeset = make_changeset(assigns.params)

    {:ok,
     socket
     |> assign(assigns)
     |> assign(:changeset, changeset)}
  end

  def handle_event("add-entry", entry_params, socket) do
    changeset = socket.assigns.changeset
    entries = Ecto.Changeset.fetch_field!(changeset, :entries)

    changeset = Ecto.Changeset.put_assoc(changeset, :entries, [EntryContext.change_entry(%Entry{}, entry_params) | entries])
    |> Map.put(:action, :validate)
    |> IO.inspect(label: :log_add_entry)

    {:noreply, assign(socket, changeset: changeset)}
  end

  def handle_event("save", _params, socket) do
    IO.inspect(params, label: :save
    {:noreply, socket}

  end
end

I’ve been trying to get this liveview form component to work correctly with no luck although I have a sister form working similarly just fine. Wonder if someone could point me in the right direction or point out what might be the issue if they happen to know why the form is behaving like such.

I’m still using liveview 0.17.11 on Phoenix 1.6.11 and elixir 1.14.0-rc.0

Any pointers are greatly appreciated and thanks in advance!

1 Like

That‘s how html works. Buttons by default submit their related form. If you don‘t want that you need to add type="button" (submit is the default type) to it.

2 Likes

@LostKobrakai you teach me a great lesson :sweat_smile:
this probably shows how I missed the obvious … how embarrassing lol
thanks for your help @LostKobrakai!!

I want to ask a out of context question.
Do you happen to encounter “add-entry” event handler being expected not in the component but in the liveview where it’s called??

I am having such issue and I add phx-target={@myself} in the button generating the event just so the “add-entry” event is handled by the form component itself even though the form contains phx-target={@myself}