Live View generator gave me a "new" button. When I clicked it I got a pile of gibberish

Hi. I ran the live view generator. When I clicked the “New” post button of my newly generated CRUD app, I received a pile of error gobbly goop. I have no idea what is wrong.

I was following a tutorial online A Beginner's Introduction to Phoenix Framework and LiveView | John Christopher - YouTube

and I did:

mix phx.new App

mix.phx.gen.live Boards Board boards title:string

I copied the routes to the routes file as prompted.

mix ecto.create
mix ecto.migrate
mix phx.server

When the app launched I went to /boards and I clicked the new button. I got a prompt saying that it couldn’t find the internet and it spat out a big pile of text below. Thank you.

Error:

key :name not found in: %{changed: nil, given: %{changed: nil, field: %Phoenix.HTML.FormField{id: “board_title”, name: “board[title]”, errors: [], field: :title, form: %Phoenix.HTML.Form{source: #Ecto.Changeset<action: nil, changes: %{}, errors: [title: {“can’t be blank”, [validation: :required]}], data: #App.Boards.Board<>, valid?: false>, impl: Phoenix.HTML.FormData.Ecto.Changeset, id: “board”, name: “board”, data: %App.Boards.Board{meta: #Ecto.Schema.Metadata<:built, “boards”>, id: nil, title: nil, inserted_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: “board_title”, name: “board[title]”, errors: [], field: :title, form: %Phoenix.HTML.Form{source: #Ecto.Changeset<action: nil, changes: %{}, errors: [title: {“can’t be blank”, [validation: :required]}], data: #App.Boards.Board<>, valid?: false>, impl: Phoenix.HTML.FormData.Ecto.Changeset, id: “board”, name: “board”, data: %App.Boards.Board{meta: #Ecto.Schema.Metadata<:built, “boards”>, id: nil, title: nil, inserted_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”}

Yup, It’s an issue.

To proceed, just add name="some_name" id="some_id" value="" errors={[]} to the input field in form_component.ex

@impl true
  def render(assigns) do
    ~H"""
    <div>
      <.header>
        <%= @title %>
        <:subtitle>Use this form to manage board records in your database.</:subtitle>
      </.header>

      <.simple_form
        for={@form}
        id="board-form"
        phx-target={@myself}
        phx-change="validate"
        phx-submit="save"
      >
        <.input field={@form[:title]} type="text" label="Title" name="some_name" id="some_id" value="" errors={[]} />
        <:actions>
          <.button phx-disable-with="Saving...">Save Board</.button>
        </:actions>
      </.simple_form>
    </div>
    """
  end


It’s happening because name, id, value are required fields. Which you can check in core_components.ex.

attr :id, :any
attr :name, :any
attr :errors, :list

But I don’t know why the Generators are not adding them.


P.S. Now I’m unable to proceed after solving that error. New errors show up when I am trying to add something. :sweat_smile:

That got rid of the initial error but it looks like a cascade.
This is about a 5th of the blob I currently got. I’ll just leave this here for the next person that stumbles into it. I don’t care to go down this path any further

[error] GenServer #PID<0.832.0> terminating
** (FunctionClauseError) no function clause matching in AppWeb.BoardLive.FormComponent.handle_event/3
(app 0.1.0) lib/app_web/live/board_live/form_component.ex:42: AppWeb.BoardLive.FormComponent.handle_event(“validate”, %{“_target” => [“undefined”]}, phoenix.LiveView.Socket<id: “phx-F0UtdHijh_TLngUD”, endpoint: AppWeb.Endpoint, view: AppWeb.BoardLive.Index, parent_pid: nil, root_pid: #PID<0.832.0>, router: AppWeb.Router, assigns: %{changed: %{}, action: :new, board: %App.Boards.Board{meta: ecto.Schema.Metadata<:built, “boards”>, id: nil, title: nil, inserted_at: nil, updated_at: nil}, flash: %{}, form: %Phoenix.HTML.Form{source: ecto.Changeset<action: nil, changes: %{}, errors: [title: {“can’t be blank”, [validation: :required]}], data: app.Boards.Board<>, valid?: false>, impl: Phoenix.HTML.FormData.Ecto.Changeset, id: “board”, name: “board”, data: %App.Boards.Board{meta: ecto.Schema.Metadata<:built, “boards”>, id: nil, title: nil, inserted_at: nil, updated_at: nil}, hidden: , params: %{}, errors: , options: [method: “post”], index: nil, action: nil}, id: :new, myself: %Phoenix.LiveComponent.CID{cid: 1}, patch: “/boards”, title: “New Board”}, transport_pid: #PID<0.645.0>, …>)
(phoenix_live_view 0.18.15) lib/phoenix_live_view/channel.ex:621: anonymous fn/4 in Phoenix.LiveView.Channel.inner_component_handle_event/4
(telemetry 1.2.1) /home/wktdev/Desktop/sandbox/app/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
(phoenix_live_view 0.18.15) lib/phoenix_live_view/diff.ex:207: Phoenix.LiveView.Diff.write_component/4
(phoenix_live_view 0.18.15) lib/phoenix_live_view/channel.ex:544: Phoenix.LiveView.Channel.component_handle_event/6
(stdlib 4.2) gen_server.erl:1123: :gen_server.try_dispatch/4
(stdlib 4.2) gen_server.erl:1200: :gen_server.handle_msg/6
(stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Last message: %Phoenix.Socket.Message{topic: “lv:phx-F0UtdHijh_TLngUD”, event: “event”, payload: %{“cid” => 1, “event” => “validate”, “type” => “form”, “uploads” => %{}, “value” => “_target=undefined”}, ref: “356”, join_ref: “355”}
State: %{components: {%{1 => {AppWeb.BoardLive.FormCom

Yup, refresh the page, I added that to my reply. :sweat_smile:

We have to wait till night time because experts come online during that hour. Or maybe we have to wait till Monday.

I’m just bumping into this as well, attempting to use the new phoenix v1.7.0-rc.3 generator.

The problem seems to be the phx.gen.live generator templates haven’t been updated to use the new form stuff (in particular I think I need to call to_form/2 somewhere… just looking into it now). Although it’s nearly bedtime here in Australia so I probably won’t get to fixing it tonight either :slight_smile:

The core components have not been updated yet to use the new form structure, so you need to add a new function head for that or call it with {form, field}.

Additionally the table component has not been updated for streams yet. You can pass the data structure to to_param or probably just use elem(row, 0) since that’s should a unique id too.

#core_components.ex:288
  def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
    if assigns.multiple do
      # left as an exercise to the reader
      raise "FormField x multiple not implemented"
    end

    assigns
    |> assign(field: nil)
    |> assign_new(:name, fn -> field.name end)
    |> assign_new(:id, fn -> field.id end)
    |> assign_new(:value, fn -> field.value end)
    |> assign_new(:errors, fn -> translate_errors(field.errors || [], field.field) end)
    |> input()
  end

# and also in def table
          <tr
            :for={row <- @rows}
            id={"#{@id}-#{Phoenix.Param.to_param(elem(row, 1))}"}
            class="relative group hover:bg-zinc-50"
          >

e: this is already fixed in master, you can see the correct generator here phoenix/core_components.ex at master · phoenixframework/phoenix · GitHub

Ok, bedtime, but…

I’m not sure if this is the best way to fix, but the key for me was to take all the places that the FormComponent was using a changeset assign, and still get the changeset, but instead use a form assign like so:

assign(socket, form: to_form(changeset))

Then, in your .simple_form function components you can use the @form syntax described here.

Hope that helps.

you should probably change the title to mention the phoenix version and actual error. so something like “Phoenix 1.7 RC3 :name key not found in forms”.

i’m battling this as well. but i’m trying to migrate my RC2 stuff to RC3. phoenixdiff.org is of some help, but this particular :name thing has got me stumped.

the core of the issue seems to be that the :name field should be generated by def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do in the core_components.ex, but I can’t figure out where the FormField is supposed to originate from so this function is never called. the docs aren’t too helpful to figure out what this is and why. and the Form docs aren’t updated either.

all in all the reason docs aren’t updated may be that Phoenix.HTML is being deprecated.

I think overall @benswift’s solution with to_form() is correct, but i’m currently dealing with the login form, which doesn’t seem to have a changeset from phx.gen.auth. i’ll go check if that’s updated.

edit: oh, it is in fact updated. so all in all to_form() is the solution with or without changesets. too bad phoenixdiff.org doesn’t have phx.gen.auth included. would have solved this already.

I had the same issues migrating from rc2 → rc3 and as @soup already mentioned the solution is to update your core_components.ex file to the one from master phoenix/core_components.ex at master · phoenixframework/phoenix · GitHub

But then you also need to update your own form code to use the new form syntax as well. It’s quite different. I ended creating a new app from scratch and generating liveviews to try and figure out what the difference was. Here’s what a form_component.ex now looks like. There’s no let={f} on the simple_form for example and individual inputs just take the field={@form[:key]} rather than the old syntax which looked like field={{f, :key}}.

  def render(assigns) do
    ~H"""
    <div>
      <.simple_form
        for={@form}
        id="chart-form"
        phx-target={@myself}
        phx-change="validate"
        phx-submit="save"
      >
        <.input
          field={@form[:source]}
          type="select"
          options={@source_options}
          label="Source"
        />
        <.input field={@form[:name]} type="text" label="Name" />
        <:actions>
          <.button phx-disable-with="Saving...">Save Chart</.button>
        </:actions>
      </.simple_form>
    </div>
    """
  end

I hope this helps, it’s just a bit of fiddling and it all works as before

2 Likes

had to resort to generating a fresh project and using those files also. but it’s working now.

i found VS Code’s “File: Compare Active File with Clipboard” command very helpful here since i had changed many of the generated files.

1 Like