I converted a LiveComponent
to a LiveView
in order to support an async Task
. When my code was in a LiveComponent
, my phx-change
fired for my input
, and my phx-click
fired for my button
. Now that the code’s inside a LiveView
, I deleted the phx-target={@myself}
from both fields and the input event has gone silent. I still get the phx-click
from the button
, but don’t even see any messages about unhandled events for the input
. Why does input
work in LiveComponent
but not LiveView
?
def render(assigns) do
~H"""
<div>
<input value={@query} name="query" phx-change="change_query" />
<button phx-click="search" type="button">Search</button>
</div>
"""
end
def handle_event("change_query", %{"query" => query}, socket) do
{:noreply, assign(socket, query: query)}
end
def handle_event("search", %{}, socket) do
{:noreply, assign(socket, loading: true)}
end
is this inside a form? phx-change
events are only emitted when inside a form AFAIK.
1 Like
Yes, it’s inside a form. Though that form is higher up in the hierarchy so maybe that’s messing things up?
LiveView
|- LiveComponent with form
|- LiveComponent
|- LiveView w/ problemantic input
This same hierarchy worked when that last LiveView
was a LiveComponent
Mmh… that looks like quite a complex hierarchy of views and components. I haven’t checked, but I suspect that a form spread across 2 LiveViews (and thus 2 processes) might cause problems. I would probably try to simplify and make sure you’re dealing with only 1 LiveView.
I’d love to just have one LiveView, but sadly handle_info
isn’t supported by LiveComponent. So to have a self-contained component that can do async work, I had to convert it to a LiveView. It’s definitely ugly since LiveComponent and LiveView are declared and pass values differently, but I’m not sure what else to do.
An other option is to use tasks and send_update
for asynchronous work in live components.
https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#send_update/3
2 Likes
Oh wow- yeah that worked. I’m not sure why I was finding much more complex solutions. The last part that tripped me up is I had to follow the docs precisely and call self()
outside of my task. Putting it inside the task returned some other value that didn’t track back to my component:
def handle_event("search", %{"query" => query}, socket) do
pid = self()
Task.start(fn ->
{:ok, results} = Ido.Media.PhotoApi.search(query)
send_update(pid, __MODULE__, id: socket.assigns.id, search_results: results)
end)
{:noreply, assign(socket, loading: true)}
end
Thanks everyone!
1 Like