Sometimes I have components that sends some message to another component and it needs to get a message back.
For example, let’s say I have a table component and a filter component, when I select a filter and click Apply
, the apply button will change to its loading state and send a message (via send_update
) to the table component to reload its data with the new filter applied.
The thing is, if I only use LV’s built-in loading capabilities (phx-click-loading
), the Apply
button will just have the loading state until its event returns, meaning that there will be a “time window” where the button will not have the loading state anymore and the table didn’t reload the data yet (more noticeable if there is some latency).
To remedy that, I was thinking about sending a callback to the table component, something like this:
# Code from the filter component
def handle_event("apply_filter", filters, socket) do
on_done = fn -> send_update(@myself, op: :done) end
send_update(Table, id: "table", filters: filters, on_done: on_done)
{:noreply, assign(socket, loading?: true)}
end
Now, at the table component, I can do something like this:
def update(%{filters: filters} = assigns, socket) do
%{on_done: on_done} = assigns
# do stuff with filters and load new data
...
# after we are done with loading stuff, call the on_done callback
on_done.()
{:ok, ...}
end
Finally, back at the filters component, I can handle the callback:
def update(%{op: :done}, socket), do: {:ok, assign(socket, loading?: false)}
So, basically, with this, my Apply
button will stay in the loading state until the data is finished loading in the table component regardless on how much time that takes.
Now, my question is, is this a good way to handle these cases? Is there a better way?