Hello,
I’m currently struggling while programming the following reusable auto-complete component:
defmodule AppWeb.AutoCompleteField do
use AppWeb, :component
defmacro __using__(opts \\ []) do
fun = Keyword.fetch!(opts, :search_function)
quote do
@impl true
def handle_event("search", %{"_target" => [name]} = params, socket) do
%{^name => value} = params
%{id: id} = socket.assigns
pid = self()
spawn(fn →
items = unquote(fun).(Map.fetch!(params, name))
send_update(pid, __MODULE__, id: id, items: items)
end)
{:noreply, socket}
end
@impl true
def handle_event("select", params, socket) do
IO.inspect(params, label: "select")
# TODO: send_update
{:noreply, assign(socket, items: [])}
end
@impl true
def handle_event("select", %{"index" => index}, socket) do
index = String.to_integer(index)
value = Enum.at(socket.assigns.items, index)
{:noreply, assign(socket, items: [], value: value)}
end
end
end
attr :items, :list, default: []
attr :"list-class", :string, default: ""
attr :"item-class", :string, default: ""
attr :"container-class", :string, default: ""
attr :rest, :global
def autocomplete_field(assigns) do
~H"""
<div class={Map.get(assigns, :"container-class")}>
<input
role="combobox"
type="text"
{@rest}
phx-change="search"
phx-debounce="500"
aria-controls="options"
aria-expanded="false"
/>
<%= if @items != [] do %>
<ul role="listbox" class={Map.get(assigns, :"list-class")}>
<%= for {suggestion, index} <- Enum.with_index(@items) do %>
<li
role="option"
class={Map.get(assigns, :"item-class")}
phx-click="select"
phx-value-index={index}
>
<%= render_slot(@inner_block, suggestion) %>
</li>
<% end %>
</ul>
<% end %>
</div>
"""
end
end
It mostly works, the only problem is this that the first event, the debounced search
is properly sent to the parent live view like this:
[debug] HANDLE EVENT
Component: AppWeb.LocationLive.FormComponent
View: AppWeb.LocationLive.Index
Event: "search"
Parameters: %{"_target" => ["name"], "name" => "a"}
But the following select
event is sent incorrectly, hence the missing Component debug statement:
[debug] HANDLE EVENT
View: AppWeb.LocationLive.Index
Event: "select"
Parameters: %{"index" => "0", "value" => 0}
Any ideas what I’m doing wrong? Or understand incorrectly?