ashrafhasson
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!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #elixirconf-eu
- #metaprogramming
- #hex










Showing Posts 1 to 5- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
f0rest8
Quick thought is that the field you’re trying to match on to delete is a virtual field so it doesn’t exist when accessing it. Have you tried matching on the
:idrather than the:temp_idfor deleting it?ashrafhasson
@f0rest8 my understanding is that a virtual field should exist but is just not persisted. I tried the
:idfield but that seems to reference the Phoenix.HTML.Form interpolatedidwhich is sent back as"customer-form_contacts_0", I have no reference to that before the form is rendered. This is why I thought using a:temp_idset to a random value is maybe a good approach ..ashrafhasson
and if I try
c.data.idI get an empty%{}value backf0rest8
Yea I’m not totally sure but when I’ve used an embedded schema in the form, I did something like this…
ashrafhasson
I was able to get over this issue by utilizing the value of the hidden input field for
. Not sure why I’ve not thought of using that lol
:temp_id@f0rest8 this is very similar to what you do with referencing the index but I used the value like so: