Key :name not found in: %{__changed__: %{action: true, flash: true, ...}

I’m a beginner with phoenix and liveview and I started a personal project called “Builders”. After run the
mix phx.gen.live command for a Project entitie and run mix ecto.migrate I open my browser in http://localhost:4000/projects/new and see the error:

KeyError at GET /projects/new

Exception:

** (KeyError) key :name not found in: %{__changed__: nil, __given__: %{__changed__: nil, field: %Phoenix.HTML.FormField{id: "project_title", name: "project[title]", errors: [], field: :title, form: %Phoenix.HTML.Form{source: #Ecto.Changeset<action: nil, changes: %{}, errors: [title: {"can't be blank", [validation: :required]}, user_id: {"can't be blank", [validation: :required]}, budget: {"can't be blank", [validation: :required]}, description: {"can't be blank", [validation: :required]}], data: #Builders.Jobs.Project<>, valid?: false>, impl: Phoenix.HTML.FormData.Ecto.Changeset, id: "project", name: "project", data: %Builders.Jobs.Project{__meta__: #Ecto.Schema.Metadata<:built, "public", "projects">, id: nil, budget: nil, description: nil, title: nil, user_id: nil, created_at: nil, updated_at: nil}, hidden: [], params: %{}, errors: [], options: [method: "post"], index: nil, action: nil}, value: nil}, label: "Title", type: "text"}, field: %Phoenix.HTML.FormField{id: "project_title", name: "project[title]", errors: [], field: :title, form: %Phoenix.HTML.Form{source: #Ecto.Changeset<action: nil, changes: %{}, errors: [title: {"can't be blank", [validation: :required]}, user_id: {"can't be blank", [validation: :required]}, budget: {"can't be blank", [validation: :required]}, description: {"can't be blank", [validation: :required]}], data: #Builders.Jobs.Project<>, valid?: false>, impl: Phoenix.HTML.FormData.Ecto.Changeset, id: "project", name: "project", data: %Builders.Jobs.Project{__meta__: #Ecto.Schema.Metadata<:built, "public", "projects">, id: nil, budget: nil, description: nil, title: nil, user_id: nil, created_at: nil, updated_at: nil}, hidden: [], params: %{}, errors: [], options: [method: "post"], index: nil, action: nil}, value: nil}, inner_block: [], label: "Title", multiple: false, prompt: nil, rest: %{}, type: "text"}
    (builders 0.1.0) lib/builders_web/components/core_components.ex:350: anonymous fn/2 in BuildersWeb.CoreComponents."input (overridable 1)"/1
    (builders 0.1.0) /home/danubio/Documentos/projetos/builders/lib/builders_web/live/project_live/form_component.ex:24: BuildersWeb.ProjectLive.FormComponent.render/1
    (elixir 1.14.2) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:396: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:544: anonymous fn/4 in Phoenix.LiveView.Diff.traverse_dynamic/7
    (elixir 1.14.2) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:396: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:544: anonymous fn/4 in Phoenix.LiveView.Diff.traverse_dynamic/7
    (elixir 1.14.2) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:396: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:544: anonymous fn/4 in Phoenix.LiveView.Diff.traverse_dynamic/7
    (elixir 1.14.2) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:396: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:544: anonymous fn/4 in Phoenix.LiveView.Diff.traverse_dynamic/7
    (elixir 1.14.2) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:396: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:717: Phoenix.LiveView.Diff.render_component/9
    (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:662: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6

My lib/builders_web/live/project_live/form_component.ex is this:

 @impl true
  def render(assigns) do
    assigns |> dbg()

    ~H"""
    <div>
      <.header>
        <%= @title %>
        <:subtitle>Use this form to manage project records in your database.</:subtitle>
      </.header>

      <.simple_form
        for={@form}
        id="project-form"
        phx-target={@myself}
        phx-change="validate"
        phx-submit="save"
      >
        <.input field={@form[:title]} type="text" label="Title" />
        <.input field={@form[:user_id]} type="text" label="User" />
        <.input field={@form[:budget]} type="number" label="Budget" step="any" />
        <.input field={@form[:description]} type="text" label="Description" />
        <:actions>
          <.button phx-disable-with="Saving...">Save Project</.button>
        </:actions>
      </.simple_form>
    </div>
    """
  end

The error came from this function in lib/builders_web/components/core_components.ex:

 def input(assigns) do
    ~H"""
    <div phx-feedback-for={@name}>
      <.label for={@id}><%= @label %></.label>
      <input
        type={@type}
        name={@name}
        id={@id || @name}
        value={@value}
        class={[
          input_border(@errors),
          "mt-2 block w-full rounded-lg border-zinc-300 py-[7px] px-[11px]",
          "text-zinc-900 focus:outline-none focus:ring-4 sm:text-sm sm:leading-6",
          "phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400 phx-no-feedback:focus:ring-zinc-800/5"
        ]}
        {@rest}
      />
      <.error :for={msg <- @errors}><%= msg %></.error>
    </div>
    """
  end

I’m using phoenix in 1.7.0 and liveview in 0.18.3

Anyone can help me with this or explain me the reason error?

I believe you are mixing two versions of the generated code. If you are passing a Phoenix.HTML.FormField to your input component, you can do something like this:

def input(assigns) do
   ~H"""
   <div phx-feedback-for={@field.name}>
     <.label for={@field.id}><%= @label %></.label>
     <input
       type={@type}
       name={@field.name}
       id={@field.id}
       value={@field.value}
       class={[
         input_border(@errors),
         "mt-2 block w-full rounded-lg border-zinc-300 py-[7px] px-[11px]",
         "text-zinc-900 focus:outline-none focus:ring-4 sm:text-sm sm:leading-6",
         "phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400 phx-no-feedback:focus:ring-zinc-800/5"
       ]}
       {@rest}
     />
     <.error :for={msg <- @errors}><%= msg %></.error>
   </div>
   """
 end
1 Like

Where I can pass a Phoenix.HTML.FormField to input component? My lib/builders_web/live/project_live/index.ex is this:

defmodule BuildersWeb.ProjectLive.Index do
  use BuildersWeb, :live_view

  alias Builders.Jobs
  alias Builders.Jobs.Project

  @impl true
  def mount(_params, _session, socket) do
    {:ok, stream(socket, :projects, Jobs.list_projects())}
  end

  @impl true
  def handle_params(params, _url, socket) do
    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
  end

  defp apply_action(socket, :edit, %{"id" => id}) do
    socket
    |> assign(:page_title, "Edit Project")
    |> assign(:project, Jobs.get_project!(id))
  end

  defp apply_action(socket, :new, _params) do
    socket
    |> assign(:page_title, "New Project")
    |> assign(:project, %Project{})
  end

  defp apply_action(socket, :index, _params) do
    socket
    |> assign(:page_title, "Listing Projects")
    |> assign(:project, nil)
  end

  @impl true
  def handle_info({BuildersWeb.ProjectLive.FormComponent, {:saved, project}}, socket) do
    {:noreply, stream_insert(socket, :projects, project)}
  end

  @impl true
  def handle_event("delete", %{"id" => id}, socket) do
    project = Jobs.get_project!(id)
    {:ok, _} = Jobs.delete_project(project)

    {:noreply, stream_delete(socket, :projects, project)}
  end
end

Anyway, I tried your suggestion and the modal for create the resource appears to me. But now, when I type any key in the input, a error flashes with the message “We can’t find the internet” on a toast and after this I cant type in the input field anymore.

When you access form like that, you get a FormField.

I got two comments. On a tactical level, I’d suggest you try using dbg() to understand what’s going on. In your particular case, you can use it inside the template like this:

` <.input field={@form[:title] |> dbg() } type="text" label="Title" />`

As a broader note, read this docs: Form bindings — Phoenix LiveView v0.20.2 , they are great!

I find a issue on Github about it: "We can't find the internet" flashes on Page transitions and reloads on Firefox 106.0.5 on Phoenix 1.7-rx.0 · Issue #5102 · phoenixframework/phoenix · GitHub

Anyway, I’m trying debbuging this to find the error. Thanks for your comments!

Hi! This solution works for me:

In lib/builders_web/components/core_components.ex:

def input(assigns) do
    ~H"""
    <div phx-feedback-for={@field.name}>
      <.label for={@field.id}><%= @label %></.label>
      <input
        type={@type}
        name={@field.name}
        id={@field.id || @field.name}
        value={@field.value}
        class={[
          input_border(@field.errors),
          "mt-2 block w-full rounded-lg border-zinc-300 py-[7px] px-[11px]",
          "text-zinc-900 focus:outline-none focus:ring-4 sm:text-sm sm:leading-6",
          "phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400 phx-no-feedback:focus:ring-zinc-800/5"
        ]}
        {@rest}
      />
      <.error :for={msg <- @field.errors}><%= elem(msg, 0) %></.error>
    </div>
    """

The msg was passed directly but it has a invalid format to be rendered in html. I just access the error message getting the first element on tuple.

1 Like