I have a component which accepts an event as a prop. I want to trigger that event from within the handle_event
of the component. Sometimes it will be triggered by JavaScript events, but sometimes it would be triggered from code.
For example, the parent is managing the state of various modal forms to ensure only one can be open at a time. It passes an event to its children to use to know when the modal should close (because it was closed via button click, escape, or successful form submission). The forms need to do cleanup in the case of cancel (clear the form), or in the case of submit (save the form and clear) prior to then sending this event to the parent component.
Code example:
defmodule ModalForm do
use Surface.LiveComponent
# This event closes the modal on clicks on the cancel,
# close buttons, but the modal also needs to close
# when the data gets saved.
prop close, :event, required: true
data changeset, :struct
def handle_event("submit", form_data, socket) do
# Do some things here, for example, save the data
save(form_data)
socket = clear_form(socket)
# Now send the close event to the parent,
# so we can close the modal.
# How can we do this?
pid = self()
Task.async(fn ->
# Psuedo-code. Event name and target are in socket.assigns[:close]
propagate_event(pid, socket.assigns[:close])
end)
{:noreply, socket}
end
end
defmodule ParentComponent do
use Surface.LiveComponent
data form, :string
def handle_event("project-form-close", _, socket) do
{:noreply, assign(socket, form: nil)}
end
def render(assigns) do
~H"""
<ModalForm id="project-form" close="project-form-close" />
<ModalForm id="another-modal-form" close="another-form-close" />
"""
end
end
Is it possible to implement propagate_event
psuedo-code above?
I realize I could send a regular message and then handle it, but trying to understand whether the existing events, handlers, and props can be used in this way to avoid highly coupling all the messages from different modules.