CONTEXT: I have a child component that collects country, state_region and city data and returns a geo_point (with timezone, latlong, etc). The parent can either be a LiveView OR another component.
ISSUE: Using send self() always sends the data up to the LiveView, but I need it to sometimes go to another component. So now I have the code below to switch between send self() and send_update depending on the parent_type. It also means that to use this component, the parent liveview or component must set a “parent_type” assign of either “component” or “liveview.”
This works but seems a bit clunky to me. Am I doing this right?
defp notify_parent(socket) do
data = { %{"geo_status" => socket.assigns.geo_status,
"geo_point" => socket.assigns.geo_point,
"country" => socket.assigns.country,
"state" => socket.assigns.state,
"city" => socket.assigns.city }}
case socket.assigns.parent_type do
"liveview" -> send self(), {:geo_data, data}
"component" -> send_update(socket.assigns.module,
id: socket.assigns.parent_id,
update: :geo_data, data: data)
end
socket
end
This works but seems a bit clunky to me. Am I doing this right?
I would say it’s very clunky. A component shouldn’t have to know who its parent is in order to communicate with it, there should be one API. But, as @benwilson512 said, this is currently the right way.
Unifying the API for communicating with LiveViews and LiveComponents is AFAIK ongoing work and was mentioned by Chris McCord during his talk at Elixirconf 2022.
@myself is nil in the case of a LiveView or a Phoenix.LiveComponent.CID struct in the case of a live component but IMHO the send_update/3 function needs another kind of id for its id key in the assigns. Also we need to provide the module as part of the call. Thus I don’t know how to use @myself to solve the problem. I ended up using the notify_parent function by @annad .