Submit button doesn't work after first use

Hi everyone,

I’m trying to ramp on Phoenix/LiveView by building a simple ToDo app (of course).

I have a table of Todos and an extra row with a form to add a new one. For some reason, when I:

  1. click the submit button while the form is empty
  2. successfully add a new Todo and try to add a second
  3. sometimes delete a Todo

the submit button doesn’t seem to work after. The form won’t submit, the terminal console sees no logs, etc.

Do you know what I may be doing wrong here? To my knowledge, the live-view is clearly refreshing the list of todos; do I need to force a refresh of the form too somehow?

Also, the third cause I noted above is spurious. Sometimes it causes the form to be unusable, sometimes it doesn’t.

Here is the code:

index.html.heex
<table>
    <thead>
        <tr>
            <th>Title</th>
            <th>Description</th>

            <th></th>
        </tr>
    </thead>
    <tbody id="todos">
        <%= for todo_id <- @todo_ids do %>
            <.live_component module={PromisedWeb.PromiseLive.ShowComponent}
                             id={todo_id} />
        <% end %>
        <tr>
            <form
                phx-submit="create">
                    <td>
                        <input
                            type="text"
                            name="title"
                            placeholder="Add a Todo..."
                            spellcheck="false"
                            autocomplete="off"
                        />
                    </td>
                    <td>
                        <input
                            type="text"
                            name="description"
                            spellcheck="false"
                            autocomplete="off"
                        />
                    </td>
                    <td>
                        <%= submit "Add", phx_disable_with: "Adding..." %>
                    </td>
            </form>
        </tr>
    </tbody>
</table>
index.ex
defmodule PromisedWeb.PromiseLive.Index do
  use PromisedWeb, :live_view

  alias Promised.Todos

  @impl true
  def mount(_params, _session, socket) do
    {:ok, assign(socket, :todo_ids, list_todo_ids())}
  end

  @impl true
  def handle_event("create", todo, socket) do
    IO.inspect("handling event create")

    case Todos.create_todo(todo) do
      {:ok, _todo} ->
        {
          :noreply,
          socket
          # |> put_flash(:info, "Todo created successfully")
          |> assign(:todo_ids, list_todo_ids())
        }

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

  @impl true
  def handle_event("delete", %{"id" => id}, socket) do
    todo = Todos.get_todo!(id)

    case Todos.delete_todo(todo) do
      {:ok, _} ->
        {:noreply,
         socket
         |> assign(%{todo_ids: list_todo_ids()})}

      _ ->
        {:noreply, socket}
    end
  end

  @impl true
  def handle_info({:updated_todo, %{todo_id: _todo_id}}, socket) do
    {:noreply,
     socket
     |> put_flash(:info, "Todo updated successfully")
     |> assign(%{todo_ids: list_todo_ids()})}
  end

  defp list_todo_ids do
    Todos.list_todo_ids()
  end
end

Hi and welcome!

A form cannot be placed inside a table like that. Here’s more information with a template very similar to yours.

Try moving your form within the table cell and let us know how it goes.

1 Like

I changed the table into an unordered list and the issue seems to be resolved.

Thanks so much! I never realized tables and forms were so finnicky until now.

1 Like