Submitting multi inputs types in Phoenix LiveView

Hello everybody,
Iam new to Phoenix Components, I have tried form inside LiveView and it was amazing, but I have an issue :
form is created by Phoenix.Component.to_form/2 which transform a changeset to a form and we can use <.input type = "text" field = {@form[:somefield]} to represent a form’s field and the user’s data will be found in handle_event("submit", %{"user" => data}, socket) after submitting the form, Okay that’s fine.
But how about other inputs types than <.input type = "text"> ?
For example if we want to implement a template where someone can Signup a new account :
he has some <.input type = "text">s like username, email, password and he has to choose from a “Radio Button” between Man and Woman and he has to choose a date of birth from “Scroll Lists”…
So how we can implement that ? and the most important how we can retrieve user’s entered data in handle_event("submit"....) ?
I have searched about and I couldn’t find docs or examples, so I will be thankful for your answers.

With the new core components like <.input ...> and <.modal>, they’re just functions that are defined and documented within your Phoenix app in lib/hello_web/components/core_components.ex .

So while the type attribute defaults to "text", it also accepts a whole bunch of other values including "radio" as well as "date".

  attr :type, :string,
    default: "text",
    values: ~w(checkbox color date datetime-local email file hidden month number password
               range radio search select tel text textarea time url week)
2 Likes

Thank you @codeanpeace,
Considering we have used no-text type for an <.input> for example “Multi Select List”, how we can retrieve user’s input in handle_event/3 after submitting ?

Hi @Sidi_Mohammed , kindly asking if you can elaborate more or provide more context on your question, perhaps even a simple example of what you are trying to archieve?

1 Like

@jmnda I gave an example of Signing up

Just want to understand what you mean here:

Are you trying to implement a Multi Select input?

1 Like

Exactly @jmnda, I want to implement a list which the user can select multi values, how we can implement that please ? and how we can retrieve the selected values in handle_event/3 when submitting the form ?

1 Like

Did you search for it on these forums?
https://elixirforum.com/search?q=Multi%20select

1 Like

Use can pass a multiple attribute to your input with options to select, for example:

<.input field={@form[:tags]} type="select" multiple options={[:item_1, :item_2, :item_3]} label="Tags />

As @Joep suggested, you can search on the forum, alternatively you can look at this guide, or checkout this library

2 Likes

Here’s how you can discover it for yourself!

# assuming your multi-select is within the existing user form
def handle_event("submit", %{"user" => data}, socket) do
  IO.inspect(data)
  # and optionally when running `iex -S mix phx.server`
  require IEx; IEx.pry
  ...
  {:noreply, socket}
end

# or more generally
def handle_event("submit", params, socket) do
  IO.inspect(params)
  ...
end
2 Likes

I sword I have thinked the same thing to show the data’s map and see what’s happening :joy::joy:, Iam just waiting until turn on my computer,
thank you a lot again @codeanpeace

Thank you @jmnda for those links

Is this what you’re looking for?
Multiselect

The options bit are a bit confusing to add if you don’t know how already. I asked someone the other day how to do it and ended up with this.
Add @options with your options in the formcomponent.ex and add :options to the socket.

  @options [
    {"Newest", "newest"}, 
    {"Oldest", "oldest"},
    {"Popular", "popular"},
    {"Least Viewed", "least viewed"},
    {"Most Popular", "most popular"}
  ]

  @impl true
  def update(%{example: example} = assigns, socket) do
    changeset = Example.change_example(example)
    {:ok,
    socket
    |> assign(assigns)
    |> assign(:changeset, changeset)
    |> assign(:options, @options)
    }
  end

Your inpute type then just needs to be set to “select” and options are obviously the :options in the socket.

:example is whatever your database field is named

<.input field={f[:example]} type="select" options={@options} />

Hope this is what you were after.
edit: No idea why I added so many random popular options lol

1 Like

Thank you @GazeIntoTheAbyss, this is so helpful, I understand the idea, that means :example field will be associated with multiple values in handle_event/3 which are selected by the user

This is what @jmnda mentionned above, with multiple attribute you can select multi values

Just last thing, as @codeanpeace has suggested, IO.inspect/1 is required to see what was happening behind scenes because we can’t make any expectation about, for example the Component Function implementation for both <.input field = {@form[:username]} type = "text"> and <.input field = {@form[:username]} type = "radio"> is here but for text we will find user’s entry in handle_event("submit", %{"user" => %{"username" => username....) but for radio we will find it in handle_event("submit", %{"user" => params, "name_of_radio_button" => username}....).
This behaviour shows that a radio button will not be treated as form’s field, so I have to handle errors manually, for example if we want to force the user to select one value from all radio buttons and if he didn’ t an error shows : “you must select a username”, how we can do that ?

Without prepending the . in <.input>, you won’t actually be calling the input/1 function in your core components that appropriately nests the input field within the form.

@codeanpeace, Iam sorry it was just a written mistake, of course I have used <.input> not <input>.
now I just want to know how to show errors manually for an <.input> which will not be handled as form’s field