I’m having an issue setting up a live view, not sure what the correct way to accomplish this is.
I have a schema (Template
) that has an embeds_many
. I’d like to be able to use nested live components to add/update the nested Operation
s.
Schema:
schema "templates" do
field :name, :string
field :notes, :string
embeds_many :operations, Operation, on_replace: :delete
end
Currently, this lives in a live FormComponent
that is a customized version of the FormComponent
that mix phx.gen.live
will add.
To add or update an Operation
, it has its own UI, which is currently in its own live component, and it pops up in a modal. The user follows some steps here to prepare their Operation
, which then has a “complete” button, which sends the event to the FormComponent
. This is "add_operation"
.
The problems I’ve had is that when adding an Operation
, the other changes to the form get lost because we create a new changeset, applying the params from the "add_operation"
event to the existing Template
in socket.assigns
. When updating the regular text inputs, I can lose the added Operation
s for the same reason. And for saving the Template
, I don’t know how to save the nested Operation
s without storing them in socket.assigns
and then manually adding them to the form params on the "save"
event.
This doesn’t seem to be quite the “nested forms” example, since the form for each nested Operation
is ephemeral.
I’ve also tried the “checkboxes” approach from Chris McCord’s recent keynote ( Keynote: The Road To LiveView 1.0 by Chris McCord | ElixirConf EU 2023 - YouTube), giving each of my fields a hidden input and then using the normal markup to display each Operation
, but I must be missing something because this doesn’t seem to actually add any items. If there are already Operation
s, the save event does seem to work as expected.
Changeset:
def changeset(template, attrs) do
template
|> cast(attrs, [:name, :notes])
|> cast_embed(:operations,
with: &Operation.changeset/2,
sort_param: :operations_order,
drop_param: :operations_delete
)
|> validate_required([:name])
end
and FormComponent
<.simple_form
for={@form}
id="template-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<.input field={@form[:name]} type="text" label="Name" />
<.input field={@form[:notes]} type="textarea" label="Notes" />
<.inputs_for :let={op_form} field={@form[:operations]}>
<input type="hidden" name="list[operations_order][]" value={op_form.index} />
<!--hidden inputs for Operation's fields-->
</.inputs_for>
<label class="...">
<input type="checkbox" phx-click="open_modal" name="list[operations_order][]" class="hidden" /> Add Operation
</label>
Has anyone here run into this kind of problem? I feel like there has got to be a sane way to use another live component to manage creation/editing of the items that are being embedded.