I’m loving the new drop_param
and sort_param
options for input forms. However, I’m finding myself trying to implement a duplication button.
Here’s what my current implementation looks like:
I can move the entries around using the three bars on the left (using sort_param
, delete entries using the X on the right (using drop_param
), and now I want to be able to duplicate entries using the last action on the right.
Is there an easy way to do that? Preferably, the new entry should appear just below the duplicated entry, pushing other entries down, but a strategy that just inserts a duplicate at the end could also work.
My first idea was to implement the duplication button using phx-click
, like this (where entry
is the bound value from an inputs_for
):
<span
class="hero-document-duplicate"
phx-click="duplicate"
phx-value-entry_id={entry.index}
/>
And then use manipulate form.params
in my handler, like so:
def handle_event("duplicate", %{"entry_id" => entry_id}, socket) do
form_params = socket.assigns.form.params
form_params =
update_in(
form_params["entries"],
fn entries ->
entries
|> Enum.map(fn {k, v} ->
{if String.to_integer(k) > String.to_integer(entry_id) do
to_string(String.to_integer(k) + 1)
else
k
end, v}
end)
|> Map.new()
|> Map.put(
to_string(String.to_integer(entry_id) + 1),
Map.delete(form_params["entries"][entry_id], "id")
)
end
)
...
end
However, in addition to looking extremely ugly, it doesn’t work because form.params
is not always set (i.e. if I duplicate a row before making any other change in the form). On the other hand, it seems unwise to just use form.data
directly, since it won’t have in-progress changes.
How would you go about implement duplication in a form like this?