Hi,
I’m still making my way around LiveView and I hope I’m missing something that will change this task to embarrassingly simple
So, I have a simple one input - on button component which only responsibility is to get an address from a user.
@impl true
def render(assigns) do
~H"""
<div>
<.form
:let={f}
for={@changeset}
id="statement-report-form"
phx-target={@myself}
phx-submit="save"
class="x__form-row"
>
<.input
class="x__input x__input--search grow"
field={{f, :address}}
type="text"
autocomplete="off"
placeholder="Place any bitcoin address here"
/>
<.button type="submit" class="x__button x__button--primary" phx-disable-with="Loading...">
Show transactions
</.button>
</.form>
</div>
"""
end
then it communicates obtained and validated address to the parent live view
def handle_event("save", %{"x_pub" => xpub_params}, socket) do
changeset =
socket.assigns.xpub
|> XPub.changeset(xpub_params)
|> Map.put(:action, :validate)
if changeset.valid? do
send(socket.root_pid, {:xpub_address_supplied, fetch_change!(changeset, :address)})
end
{:noreply,
socket
|> assign(:changeset, changeset)}
end
This report generation process can take seconds, and naturally, I want to leverage out-of-the-box form blocking functionality instead of rolling my own. But send
is asynchronous, and the component goes about its business as soon as the message is sent.
As an option, I pass a callback to the child component within which the report is generated. But it feels way too hacky.
if changeset.valid? do
socket.assigns.on_address_supplied.(fetch_change!(changeset, :address))
end
Root LiveView:
defp on_address_supplied(xpub) do
case Scanner.xpub_report(xpub) do
{:error, :server_error} ->
send(self(), {:on_report_fetched, :failure})
{:ok, report} ->
send(self(), {:on_report_fetched, :success, report["transactions"]})
end
end