Flop.Phoenix implements the Phoenix.HTML.FormData
protocol for its meta struct: flop_phoenix/lib/flop_phoenix/form_data.ex at main · woylie/flop_phoenix · GitHub
At some point, an offset
option was added to allow users to build more complex form layouts. By setting the option, the :index
, :id
, and :name
fields on the Phoenix.HTML.Form
struct are set in to_form/4
:
offset_string = Integer.to_string(offset)
%Phoenix.HTML.Form{
index: offset,
id: id <> "_" <> offset_string,
name: name <> "[" <> offset_string <> "]",
# ...
}
This worked fine with the old inputs_for
function that was moved to PhoenixHTMLHelpers
. However, this stopped working with Phoenix.Component.inputs_for/1
. I can still pass the offset
option (or any other option) to make it available in the form data implementation:
~H"""
<.inputs_for
:let={ff}
field={@form[:filters]}
options={[fields: @fields, offset: 5]}
>
<%!-- ... %>
</.inputs_for>
"""
And, given the offset `5`, the protocol implementation produces the correct values in the `Form` struct:
```elixir
%Phoenix.HTML.Form{
id: "flop_filters_5",
name: "filters[5]",
index: 5,
# ...
}
However, Phoenix.Component.inputs_for/1
appears to ignore both the index and the id that the protocol implementation produces. The form structs passed to the inner block always start with index 0 and an according ID (although the name is derived correctly from the form struct returned by the protocol implementation):
%Phoenix.HTML.Form{
id: "flop_filters_0",
name: "filters[5]",
hidden: [{"_persistent_id", "0"}, {:field, :email}],
params: %{"_persistent_id" => "0"},
index: 0
}
- Here it initializes the index with
0
instead of the index of the form struct: phoenix_live_view/lib/phoenix_component.ex at 8ea6b487de17ea1eb962f1ec37cd99e7182e5e50 · phoenixframework/phoenix_live_view · GitHub - And here it builds a new ID instead of using the one from the form struct: phoenix_live_view/lib/phoenix_component.ex at 8ea6b487de17ea1eb962f1ec37cd99e7182e5e50 · phoenixframework/phoenix_live_view · GitHub
I noticed that I can initialize the params
on the form struct produced by my protocol implementation with a _persistent_id
to achieve the previous behavior:
%Phoenix.HTML.Form{
index: index,
id: id <> "_" <> index_string,
name: name <> "[" <> index_string <> "]",
params: %{"_persistent_id" => index}
# ...
}
This leads to the correct index being used by inputs_for
, but this relies on an internal implementation detail and probably isn’t meant to be used this way.
I don’t know why it was implemented this way, and whether this was an oversight, or what the purpose of the _persistent_id
is, or whether I’m doing something wrong. Can someone more familiar with LiveView give me some insights?