Instead of writing inputs like <%= input ... %>
, I understand we should use a Phoenix.Component function.
I have a form that has 2 dates, one select and one datalist, the latter is populated via a search query when typing.
I did not find components ready to use so I guess we should write them. I believe something like the code below can be used, but it does not work as it should.
When I fill the form, it is captured by the “on-change” binding and the payload is correct. However, the input can disappear from the cell. For example, if I set the “datalist” and then the “select”, then the data list input is emptied. Same thing if I set a date, not persisted on the screen, only.
When I use the form <%= …%>, this does not happen. Furthermore, I did not change the date inputs for the moment because I have validations on them with an error-tag and I did not succeed to change them to functions till now.
Anyway, I am looking for guidance on where I can find or get inspired for these standard components.
<.form :let={f} for={@changeset} id="query_picker"
phx-submit="send"
phx-change="change"
phx-target={@myself}
>
<.datalist users={@users} phx_change={@myself}></.datalist>
<.select status={@status}></.select>
<%= date_input(f, :start_date, id: "start_date" ) %>
<%= error_tag(f, :start_date) %>
<%= date_input(f, :end_date, id: "end_date") %>
<%= error_tag(f, :end_date) %>
<button form="query_picker" >Send</button>
</.form>
def datalist(assigns) do
~H"""
<input list="datalist" id="datalist-input" name="query_picker[user]"
phx_change="search-email"
phx_target={@phx_change}
phx_debounce="500"
placeholder="enter an email"
/>
<datalist id="datalist">
<%= for user <- @users do %>
<option value={user} id={"#{user}"} />
<% end %>
</datalist>
"""
end
def select(assigns) do
~H"""
<select id="select" name="query_picker[status]">
<%= for status <- @status do %>
<option value={status}><%= status %></option>
<% end %>
</select>
"""
end
slot(:inner_block, required: true)
attr(:users, :list)
attr(:user, :string)
attr(:phx_change, :string)
# form "phx-change" handler
def handle_event("change", %{"query_picker" => params}, socket) do
changeset =
%QueryPicker{}
|> QueryPicker.changeset(params)
|> Map.put(:action, :validate)
{:noreply, assign(socket, :changeset, changeset)}
end
# fill in a datalist for users when typing
def handle_event("search-email", %{"query_picker" => %{"user" => email}}, socket) do
datalist = LiveMap.User.search(email) |> Enum.map(& &1.email)
{:noreply, assign(socket, users: datalist)}
end
# LiveMap.User.search
def search(string) do
like = "%#{string}%"
from(u in User,
where: ilike(u.email, ^like)
)
|> Repo.all()
end
For the `<%= %> version, I used a helper ( a copy of the Phoenix.HTML):
defmodule LiveMapWeb.InputHelpers do
use Phoenix.HTML
def datalist_input(opts, [do: _] = block_options) do
content_tag(:datalist, opts, block_options)
end
def option_input(user) do
content_tag(:option, "", value: user)
end
end
and use in the form:
<%= datalist_input(id: "datalist") do %>
<%= for user <- @users do %>
<%= option_input(user) %>
<% end %>
<% end %>