Hello All,
I have a customer schema with nested contacts that’s defined as an embedded schema that I render in a liveview form component. I’m trying to add and delete the nested contact dynamically. Adding works just fine but when I trigger a remove action, I can’t see the param for the newly added contact in the handle_event callback … not sure how to go about getting this to work properly, any advice on what I’m doing wrong here please?
defmodule MyApp.Customer do
use Ecto.Schema
import Ecto.Changeset
schema "customers" do
field :name, :string
embeds_many :contacts, MyApp.ContactDetail
timestamps()
end
@doc false
def changeset(customer, attrs) do
customer
|> cast(attrs, [:name])
|> cast_embed(:contacts)
|> validate_required([:name])
end
end
defmodule MyApp.ContactDetail do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :temp_id, :string, virtual: true
field :contact_type, Ecto.Enum, values: [:address, :phone, :email]
field :details, :string
end
def changeset(embedded_schema, attrs) do
embedded_schema
|> cast(attrs, [:contact_type, :details, :temp_id])
|> validate_required([:contact_type, :details])
end
end
In my customer_live/form_component.html.heex, I have something like this for the contacts section:
<.form
let={f}
for={@changeset}
id="customer-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save">
<%= for c <- inputs_for(f, :contacts) do %>
<%= hidden_inputs_for(c) %>
<%= text_input c, :details %>
<%= hidden_input(c, :temp_id) %>
<a href="#"
phx-target={@myself}
phx-click="remove-contact"
phx-value-contact={c.data.temp_id}>×</a>
<% end %>
</.form>
In the customer_live.form_component, the handle_event("remove-contact", %{"contact" => temp_id}, socket) gets called but the temp_id is empty. I tried referencing it like c.temp_id but that blows up with an error.
def handle_event("add-contact", _, socket) do
existing_contacts = Map.get(socket.assigns.changeset.changes, :contacts, [])
new_contacts = [%{temp_id: :rand.uniform(1000)} | existing_contacts]
changeset = Ecto.Changeset.put_embed(socket.assigns.changeset, :contacts, new_contacts)
{:noreply, assign(socket, changeset: changeset)}
end
def handle_event("remove-contact", %{"contact" => contact_id}, socket) do
new_contacts = socket.assigns.changeset.changes
|> Map.get(:contacts)
|> Enum.reject(&(&1.changes.temp_id == contact_id))
changeset = Ecto.Changeset.put_embed(socket.assigns.changeset, :contacts, new_contacts)
{:noreply, assign(socket, changeset: changeset)}
end
I’m using liveview 0.17.5 btw.
Appreciate any help, thanks!






















