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.