When running my LiveComponent in development everything works as expected, the handle_event function on the component itself handles the event. When i ran the exact same code in production it complains that the parent LiveView does not implement the handle_event function for that particular event.
LiveComponent
defmodule Admin.Components.TagEditor do
use Phoenix.LiveComponent
alias Noozox.Core
def render(assigns) do
~L"""
<div id="<%= @id %>">
<div class="tags">
<%= for tag <- @post.tags do %>
<span class="tag badge badge-secondary">
<%= tag.name %>
<a class="btn btn-success" phx-click="remove" phx-value-tag_id="<%= tag.id %>">X</a>
</span>
<% end %>
</div>
<form phx-submit="add" phx-change="suggest">
<div class='control-group'>
<label class='control-label' for='new_tag-input'>Tags</label>
<input type="text" name="new_tag" size="5" />
</div>
<div>
<%= Enum.join(@suggestions, ", ") %>
</div>
<div class='control-group'>
<button class="btn btn-success">Add tag</button>
</div>
</form>
</div>
"""
end
def mount(socket) do
{:ok, assign(socket, suggestions: [])}
end
def handle_event("suggest", %{"new_tag" => tag_name}, socket) do
suggestions = case String.trim(tag_name) do
nil -> []
"" -> []
tag_name -> Enum.map(Core.suggest_tags(tag_name), fn t -> t.name end)
end
{:noreply, assign(socket, post: socket.assigns.post, suggestions: suggestions)}
end
end
LiveView
<%= live_component @socket, Admin.Components.TagEditor, id: :tag_editor, post: @post %>
The error on the logs
** (FunctionClauseError) no function clause matching in NoozoxWeb.Admin.Post.EditView.handle_event/3
(noozox) lib/noozox_web/live/admin/post/edit_view.ex:70: NoozoxWeb.Admin.Post.EditView.handle_event("suggest", %{"_target" => ["new_tag"], "new_tag" => "y"}, #Phoenix.LiveView.Socket<assigns: ...>)
Any idea what i might be doing wrong, or if it could indeed be a bug?
Thanks!
Appreciate you opening this issue, I had the exact same error but also in development. This was a few days ago though, just pre 0.5 release, pointing the dep to github repo.
I actually thought I did something wrong and rewrote the components inside the LiveView instead at the moment, but I was hoping to look more at this when I had time.
You'll need to annotate the form with a phx-target like so:
<form phx-submit="add" phx-change="suggest" phx-target="#<%= @id %>">
Notice the # since the annotation has to be a query selector.
See Targeting Component Events for more information.
But why does it work like this in development then? And do you know if it's a recent change? Was working before (in LV 0.4)...
EDIT: Maybe answering my own question, because in production the component and the view might be running in separate processes? :)
EDIT2: In which case, if that's the case, it feels strange that the component doesn't send events to itself by default, instead of the other way around, right? Would be more intuitive to have the component need to specify something like phx-send-events-to-parent-view=true instead of the component saying it wants to send events to itself. If you catch my meaning...
@nocivus I would guess that your client dependency is stale. I'd try reinstalling the client dependency to ensure local dev is working correctly:
$ rm -rf assets/node_modules/phoenix_live_view
$ npm install --prefix assets
Most helpful comment
You'll need to annotate the form with a
phx-targetlike so:Notice the
#since the annotation has to be a query selector.See Targeting Component Events for more information.