I’m attempting to create a nested form with duplicate inputs for two separate ticket holders. I’m using the <.simple_form> in LiveView, and everything I’ve seen is using different syntax (i.e. <% as opposed to <.)
I have this form working:
<.simple_form :let={f} for={%{tickets: []}}>
<.input
field={f[:text]}
type="text" label="Enter text:"
autocomplete="text"
placeholder="Enter text" />
<.input
field={f[:option_id]}
type="select"
label="Choose your option:"
options={Enum.map(options, fn option -> {option.name, option.id} end)}
/>
<.input
field={f[:date]}
type="date"
label="Choose a date:"
/>
<.input
field={f[:time]}
type="time"
label="Choose a time:"
/>
<div class="flex gap-2">
<div class="w-2/3">
<.input
field={f[:weight]}
type="number"
label="Weight"
min="0"
/>
</div>
<div class="w-1/3 mt-1">
<.input
field={f[:weight_unit]}
type="select"
label="Unit"
options={Enum.map(weight_units, fn weight -> weight.unit end)}
/>
</div>
</div>
<:actions>
<.button button_type="booking">Continue</.button>
</:actions>
</.simple_form>
however when I try to add this at the top of the form to test (from the Phoenix docs):
<.inputs_for :let={fp} field={f[:tickets]}>
<.input field={fp[:name]} type="text" />
</.inputs_for>
I receive this error:
construction of binary failed: segment 1 of type 'binary': expected a binary but got: nil
with this stack trace:
id = to_string(id || form.id <> "_#{field}")
Any idea on how to create a duplicate nested form of the current simple form with a nested inputs_for? Thanks!
1 Like
jmnda
March 24, 2023, 9:07pm
2
Not sure what could be the issue. I tried to reproduced it on my end and everything is working fine. See the code below:
Schemas
defmodule MyApp.Shop.ProductCategory do
use Ecto.Schema
import Ecto.Changeset
schema "product_categories" do
field(:name, :string)
timestamps()
end
@doc false
def changeset(product_category, attrs) do
product_category
|> cast(attrs, [:name])
|> validate_required([:name])
|> unique_constraint(:name)
end
end
defmodule MyApp.Shop.Product do
use Ecto.Schema
import Ecto.Changeset
schema "products" do
field(:name, :string)
field(:price, :decimal)
belongs_to(:product_category, MyApp.Shop.ProductCategory)
timestamps()
end
@doc false
def changeset(product, attrs) do
product
|> cast(attrs, [:name, :price])
|> validate_required([:name, :price])
|> cast_assoc(:product_category)
end
end
And then in my Form:
.simple_form
for={@form}
id="product-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<.input field={@form[:name]} type="text" label="Name" />
<.input field={@form[:price]} type="number" label="Price" step="any" />
<.inputs_for :let={category_form} field={@form[:product_category]}>
<.input type="text" field={category_form[:name]} label="category" />
</.inputs_for>
<:actions>
<.button phx-disable-with="Saving...">Save Product</.button>
</:actions>
</.simple_form>
Am on LiveView 0.18.18
and Phoenix 1.7.2
. Perhaps can you try to update the Phoenix and LiveView?
When you pass a map to to_form/1
, it assumes said map contains the form parameters, which are expected to have string keys.
Maybe try string key for the map?
I do have those same LiveView and Phoenix versions. When I implemented your form, I got the following error:
key :form not found in: %{__changed__: %{flash: true, id: true}
with this stacktrace
<.simple_form
for={@form}
id="product-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
You can use to_form(map, id: …)
, but the support for map based nested forms is not great. E.g. there’s no way to pass errors to nested inputs.
KP123
May 18, 2023, 9:04pm
6
Im experiencing the same issue right now. Have you discovered a solution?
KP123
May 18, 2023, 9:14pm
7
JK passing the as option to to_form
fixed everything for me. For example:
to_form(%{
"name" => "birthday.png",
"meta" => %{byte_size: 1000, location: "path/to/file"}
}, as: "image")
1 Like
this worked for me as well, thanks
I encountered the same issue and only managed to make it work when
I defined the form_data
form_data = %{
"nested_field" => %{
"1" => %{
"subfield1" => "value 1.1",
},
"2" => %{
"subfield1" => "value 2.1",
}
}
} |> to_form(id: "nested_form")
and used inputs_for
with as
containing field name and default
containing empty list.
<.form :let={f} for={@form_data}>
<.inputs_for :let={nf} field={f[:nested_field]} as={:nested_field} default={[]}>
<.input field={nf[:subfield1]} type="text"/>
</.inputs_for>
</.form>
The following scenarios result in errors
Not setting as
on inputs_for
correctly → construction of binary failed: segment 1 of type 'binary': expected a binary but got: nil
Not setting default
on inputs_for
→ inputs are not rendered correctly, only one shows up and it is empty.
Using List instead of Map for nested_field
→ errors were found at the given arguments: * 2nd argument: not a tuple