Nested Form with map

I would like to setup a nested form using a map. The form_for and to_form accept a map and this works for a single level form.

%{"name" => "fred"} |> Phoenix.Component.to_form() # this works and allows editing the name field using html form.

but would I expect the following to work?

%{"name" => "fred", "addresses" => [
%{"street" => "12342 S. Park" },
%{"street" => "1 N. Dump Rd" },
]} |> Phoenix.Component.to_form() # ???

I am trying to build up a map that has parent with multiple children. User would have a “add more” button to add another address. I have this working using changeset and associations, but have not seen case where this works with maps.

This is only partially supported by the map based implementation. Most importantly there‘s no way to handle errors for nested inputs.

I would not be too concerned about errors…yet. Would love to get the basics working. Any I could look at for an example of something like this?

Have you tried setting up addresses as embeds together with Phoenix.Component.inputs_for/1 within the form in the template?

I don’t have a Ecto schema for this, so not sure if embeds apply. I am trying to use the input_for and so far have not been able to get very far. Latest error I get is:

* (ArgumentError) the Access calls for keywords expect the key to be an atom, got: "_persistent_id"
    (elixir 1.14.3) lib/access.ex:313: Access.get/3
    (phoenix_live_view 0.20.0) lib/phoenix_component.ex:2415: anonymous fn/2 in Phoenix.Component."inputs_for (overridable 1)"/1
    (elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 0.20.0) lib/phoenix_component.ex:2415: Phoenix.Component."inputs_for (overridable 1)"/1
    (phoenix_live_view 0.20.0) lib/phoenix_live_view/tag_engine.ex:68: Phoenix.LiveView.TagEngine.component/3

Ahh, yeah – inputs_for/1 expects an Ecto schema with either associations or embeds defined.

That‘s not true. It doesn‘t care for ecto. It requires a working Phoenix.HTML.FormData protocol implementation just like all other phoenix form APIs. The implementation for ecto certainly includes a lot of bells and whistles and I wouldn‘t call the map based implementation to be „feature complete“, but inputs_for can work with map based forms for simple cases.

Yup, good catch!

To re-clarify, to_form/1 accepts either Ecto changesets or maps and converts them into a Phoenix.HTML.Form struct.

And inputs_for/1 requires a Phoenix.HTML.FormField struct for its field attribute which you can access through an aforementioned Phoenix.HTML.Form struct.