List field type whose rows have declared keys — MishkaGervaz.Form.Types.Field.KeyMap repeated,
with rows the author can add and remove.
Use it for a {:array, :map} column whose entries have a fixed, small shape: a Phoenix slot's
attrs, a list of redirects, a set of social links. Use :json instead when the entries are not
known ahead of time.
Example
As a field of its own, over an {:array, :map} column:
field :social_links, :key_list do
options [
[name: :platform, type: :text, placeholder: "e.g. github"],
[name: :url, type: :text, placeholder: "https://…"]
]
ui do
label "Social links"
add_label "+ Add link"
end
endOr as a sub-field of a nested row, which is where a Phoenix slot's attrs lives:
nested_field :attrs, :key_list do
options [
[name: :name, type: :text, placeholder: "e.g. label"],
[name: :type, type: :select, options: ~w(string integer boolean any)],
[name: :required, type: :toggle, label: "Required"]
]
ui do
label "Slot Attributes"
add_label "+ Add Attribute"
remove_label "Remove"
end
endKeys are declared exactly as :key_map declares them, a list or fn state -> keys end — see its
docs for the options each key takes. add_label and remove_label name the two buttons; they
default to + Add and Remove.
Where it works
Both positions carry the same controls; only the events behind the two buttons differ, because the two lists sit at different depths in the params:
| Position | Column | Rows added and removed by |
|---|---|---|
| a field of its own | {:array, :map} | add_nested / remove_nested |
a sub-field of a :nested field | a constrained map | add_key_row / remove_key_row |
A sub-field only gets the buttons on the constrained-map path, where a row has an index to address. On an embedded nested field its rows still render, read-only.
Empty rows are dropped
A row whose declared keys are all blank is omitted rather than stored as a map of empty strings,
so adding a row and then leaving it costs nothing. Values are cast to their declared type before
they reach the changeset; see MishkaGervaz.Form.Types.Field.Nested.
See MishkaGervaz.Form.Behaviours.FieldType and MishkaGervaz.Form.Types.Field.
Summary
Functions
The declared keys of one row. Delegates to MishkaGervaz.Form.Types.Field.KeyMap.keys/1.
The declared keys of one row, with options fn state -> keys end read with the form state.
Delegates to MishkaGervaz.Form.Types.Field.KeyMap.keys/2.
The rows in order, whether they arrived as a list or as the index-keyed map a form posts.
Functions
The declared keys of one row. Delegates to MishkaGervaz.Form.Types.Field.KeyMap.keys/1.
The declared keys of one row, with options fn state -> keys end read with the form state.
Delegates to MishkaGervaz.Form.Types.Field.KeyMap.keys/2.
The rows in order, whether they arrived as a list or as the index-keyed map a form posts.
A form sends attrs[0][name], attrs[1][name] and so on, which Phoenix hands back as
%{"0" => …, "1" => …}; the indices give the order. A value read back off the column is already
a list and is returned as it stands. Anything that is not a map — including the hidden marker the
template posts so an empty list can be expressed at all — is dropped.
iex> MishkaGervaz.Form.Types.Field.KeyList.rows(%{"1" => %{"a" => 1}, "0" => %{"a" => 0}})
[%{"a" => 0}, %{"a" => 1}]