Working with to_form and inputs_for without Ecto & chageset

Hi,

I’m building an app that uses SurrealDB, I connect to it via RPC and I want to be able to present a form to the user that lets it add and edit some data.

So far, pretty much straight forward, no issues.
That’s what I got in my mount currently -

    form_simple = %{
      "title" => "list a",
      "category" => "movies",
      "description" => "",
      "items" => [%{"value" => "38"}]
    }
      socket
      |> assign(form: to_form(form_simple, as: "new-list"))

The issue rises when I want to enable the functionality for adding and removing more items.

For that, I’ve been trying to make -

    <.form
      :let={form}
      id="new-list"
      name="new-list"
      for={@form}
      action={~p"/user/signin"}
      class="space-y-6"
    >
.....
      <.inputs_for :let={f_items} field={form[:items]}>
        <.input type="text" field={f_items[:value]} />
      </.inputs_for>

</.form>

work.
You can ignore the action attribute, it’s WIP.

No matter what I do, I can’t find a way to render stuff via inputs_for, I’m getting different errors, for every attempt I make.

I’m getting -
the Access module supports only keyword lists (with atom keys), got: "_persistent_id",

This is only the current error, when I try other approaches, then I get other errors (a bit difficult to reproduce for the purpose of this post)

Can’t find a way to make it work.

The only option I can think of now, is to simply track the :items separately and do the appropriate work on submitting the form.

Would love to get some ideas

Hmm, I thought id be able to help you but have come a little short myself.

From comparing to how a nested form (using ecto) which works for me, it looks like this:

form_simple = %{
      "title" => "list a",
      "category" => "movies",
      "description" => "",
      "one_nest" => %{
        "_persistent_id" => "0",
        "views" => "37"
      },
      "many_nest" => %{
        "0" => %{
          "views" => "38"
        },
        "1" => %{
          "views" => "39"
        }
      }
    }

But, this doesn’t seem to be working for ecto-less form params.

A difference I noted was the value from the FormField is a list (of changesets) (despite the params of the form in the FormField being like above), so potentially there is a ‘magic’ step that is missing here when not using changesets that fiddles with the FormField’s value.

(note: I’ve renamed ‘value’ to ‘views’ in the params to avoid confusion between that value and the FormField value in my explanation)

Hope this helps in some way! It might be worth making a local fresh phoenix app and making a variant of your from with ecto to do a deeper dive on the output of the form to compare.

The easiest way to do this is to use an Ecto.Schema with an embedded_schema to drive the form.
@PJUllrich has a couple of videos about this on his Indie courses, it’s not free, but worth the investment.

2 Likes

I’m working on something similar. It seems that to_form and inputs_for is tailored to be used with Ecto.schema. When you want to use to_form with a map then inputs_for needs some options:

<.inputs_for :let={f_items} field={form[:items]} options={[id: "items", as: "items"]}>

For more information and further details I have to have a look at the Phoenix code, which I have planned for later.

1 Like

That shouldn’t be the case. There’s a protocol for different form inputs for a reason. I’d argue the observed behaviour here to be a bug with inputs_for.

1 Like

@LostKobrakai thanks for the tip. I will look into it when I have some time.