I’m trying to build a form with a select in a modal component, and I just need to retrieve the value selected. I wanted to use the form_for helper but cannot figure out how to do it without a model or a changeset. Is it possible?
Welcome @baezanat - yes, you can use form_for/3 from within a component but without a changeset.
For example, you can use an atom in place of the changeset:
<%= f = form_for :survey, "#", id: @id, phx_change: "validate", phx_target: @myself %>
<!-- inputs go here -->
</form>
and the the handle_event
callback will get the form params like so:
def handle_event("validate", %{"survey" => params}, socket) do
# do something with params
{:noreply, socket}
end
You will notice that the key "survey"
is the string version of the atom we passed to form_for
.
Also, it’s important to note that to ensure the select input keeps its selected value, you need to track the choice in your assigns. The following is a bit longer example that I hope illustrates this point:
defmodule MyAppWeb.SelectExample do
use MyAppWeb, :live_component
@impl true
def mount(socket) do
{:ok,
socket
|> assign(:choices, ["A", "B", "C"])
|> assign(:selected_choice, "")}
end
@impl true
def handle_event("validate", %{"survey" => params}, socket) do
case params["choice"] do
"" ->
{:noreply, socket}
choice ->
{:noreply, socket |> assign(:selected_choice, choice)}
end
end
end
To render the select input, you can use select/4:
<%= label(f, :choice) %>
<%= select(f, :choice, @choices, selected: @selected_choice) %>
or if you would prefer to build the select by hand, use options_for_select/2:
<select name="<%= input_name(f, :choice) %>" required>
<option value=""<%= if @selected_choice == "", do: ~S( selected) %>>Choose one</option>
<%= options_for_select(@choices, @selected_choice) %>
</select>
Do note that the form inputs will need to have their value:
option set manually since there isn’t a way to drive it from the base form input.
Thank you! This is exactly what i was looking for.
So I’m not able to get this to work. What am I doing wrong? I wasn’t able to get your syntax to work.
No matter what it just keeps submitting the default way:
no function clause matching Index.handle_event("alert", %{"_csrf_token" => "1223-456"}, Phoenix.LiveView.Socket...
Example:
<%= form_for :survey, "#", [phx_submit: "alert", employee_id: @current_employee.id, user_id: user.id], fn _f -> %>
....
def handle_event("alert", %{"survey" => params}, socket) do
...
It only allow a list of params inside square brackets, else error.
How can I make the params go through?