LiveComponent's handle_event gets called on server restart, seemingly for no reason, how to debug event triggers?

Hi!

I have a Phoenix LiveView, with a nested LiveComponent. It works as expected, except when the client reconnects after a server restart, because then handle_event("save", params, socket) is called. AFAIK It should only be triggered by a "change" event of its corresponding form (at least, I did not find anything in the codebase that suggests otherwise).

  <.form
    let={f}
    for={@changeset}
    id={"dependency_form_#{@changeset.data.parent_id || :new}-#{@changeset.data.child_id}"}
    phx-target={@myself}
    phx-change="save"
  >
    <%= number_input(f, :child_id, style: "display: none") %>

    <%= select(f, :parent_id, @task_options, prompt: "Select this task's parent") %>
    <%= error_tag(f, :parent_id) %>
    <!-- Hack: the error tag doesn't show for cyclicity for some reason -->
    <%= if is_cyclic_error?(@changeset) do %>
      <span class="invalid-feedback"><%= get_error_message(@changeset) %></span>
    <% end %>
  </.form>

I also checked whether the change event gets called for some reason on reconnect, but that doesn’t seem to be the case:

setTimeout(() => {
  document.querySelectorAll("form").forEach((element) => {
    element.addEventListener("change", () => console.log("I'm called"));
  });
});

I got so desperate I set up the debugger in VSCode, but it’s not triggered in debug mode.

I’m a bit lost could anyone please provide some pointers on where to look next?

Thanks!

What you’re observing is the automatic form recovery process. You can read more about it here Form bindings — Phoenix LiveView v0.18.3

Basically what’s happening is that when the page reconnects the LiveView JS re-sends the form data to the server so that the live view Elixir process can get back in sync with content that’s been entered into the form. If it didn’t, the form would be reset and the inputs would be lost on reconnect.

2 Likes

Oh, I see! Thanks! :sweat_smile: