Phoenix LiveView Form Select Fields

Firstly, thanks for the work put into LiveView!

I created a live form with LiveView and validations are working as expected, but I have a use case to set the value of a select field on the backend based on other changes (i.e. If XX value is added to an input, then change a select field value). The actual use case is when a customer is selected, the corresponding addresses fields are autopopulated in the other parts of the form.

I’ve tried setting the field to a different value using Changeset.put_change/3 and it works great for text_inputs but refuses to update select fields even though it’s reflected correctly in the changeset that is passed to the front end. In addition, I’ve tried using assign variables and passed them to the select input value, but it’s the same issue.

Below is a small example where on the handle_event(“validate”), the changeset changes are updated to gender: “Male” and username: “john_doe”. The username updates correctly, but the select input never updates on the frontend, even though if you inspect the changeset the changes are reflected properly.

Here’s the form:

<%= f = form_for @changeset, "#", [phx_change: :validate, phx_submit: :save] %>
  <%= label f, :username %>
  <%= text_input f, :username %>
  <%= error_tag f, :username %>

  <%= label f, :email %>
  <%= text_input f, :email %>
  <%= error_tag f, :email %>

  <%= label f, :gender %>
  <%= select f, :gender, ["Male", "Female"], prompt: "Select a gender" %>
  <%= error_tag f, :gender %>

  <%= label f, :phone_number %>
  <%= text_input f, :phone_number %>
  <%= error_tag f, :phone_number %>

  <div>
    <%= submit "Save", phx_disable_with: "Saving..." %>
  </div>
</form>

<p><%= inspect @changeset %></p>

Here’s the LiveView:

...
def mount(_session, socket) do
    {:ok,
     assign(socket, %{
       changeset: Accounts.change_user(%User{})
     })}
  end

  def render(assigns), do: Phoenix.View.render(DemoWeb.UserView, "new.html", assigns)

  def handle_event("validate", %{"user" => params}, socket) do
    changeset =
      %User{}
      |> Demo.Accounts.change_user(params)
      |> Ecto.Changeset.put_change(:gender, "Male")
      |> Ecto.Changeset.put_change(:username, "john_doe")
      |> Map.put(:action, :insert)

    {:noreply, assign(socket, changeset: changeset)}
  end
...

Using this code, if I start typing a phone number in the form, the username is auto set to john_doe based on the changeset, but the select input does not change to “Male” in this case.

Not sure if I’m doing something incorrectly or it’s an issue with LiveView or Morphdom.

Thanks for the help!

2 Likes

Hello, I’ve got identical problem using LiveView. I can additionally say that selects don’t change even using JavaScript. Any solution was found already?

@kaquadu At the time I ended up add a on-blur event on the select element to trigger an event to be handled by the server. I haven’t revisited this much, but you should get much better results using the new JS hooks in Phoenix LiveView.