Fill in form fields automatically

I’m currently trying to create a registration form in “liveview”, which fetch information from an API function.

How do I create a field on my “form” that automatically fills in other fields?

api = MyProject.Test.example()

Outcome

%{one: "123456", two: "MY NAME", three: "Test 1"}

Registration Form


<%= f = form_for @changeset, "#",
  id: "example-form",
  phx_target: @myself,
  phx_change: "validate",
  phx_submit: "save" %>

    <div class="form-group">
      <label>Number ONE</label>
      <%= number_input f, :number, class: "form-control" %>
      <%= error_tag f, :number %>
    </div>

    <div class="form-group">
      <label>Name TWO</label>
      <%= number_input f, :name, class: "form-control" %>
      <%= error_tag f, :name %>
    </div>

    <div class="form-group">
      <label>Select Three</label>
     <%= select(f, :options, [
      "Test 1": "Test 1",
      "Test 2": "Test 2",
      "Test 3": "Test 3"], prompt: "Select options", class: "form-control") %>
      <%= error_tag f, :name %>
    </div>

</form>

As you can see in the example above.
Would it be possible for the user to fill in the number “123456” and the other fields to be filled in automatically with liveview?

I don’t think it’s specific to liveview, but to how form works.

How would You set the value of an input? With the attribute value of the input :slight_smile:

You could always put logic in your phx_change event to put_change/3 into your changeset. Seeing that your changeset will update, your values should be reflected in your form as well.

3 Likes

In this case I would put inside the “validate” function?
The idea and the user doesn’t have to submit to show the value
phx_change: "validate"
Do you have an example for this?

I was thinking of using something like “phx-blur” and “phx-focus”

If you only want to validate on blur, you can add phx_debounce: "blur" to the field itself. Then in your validate function, you could use some conditional or DB query or whatever you need to add new params:

def handle_event("validate", %{"mystruct" => params}, socket) do
  new_params =
    case params["number"] do
      "123456" ->
        params |> Map.put("name", "MY NAME") |> Map.put("options", "Test 1")
      "etc" ->
        ...
    end

  changeset =
    %Mystruct{}
    |> Mystruct.change_mystruct(new_params)
    |> Map.put(:action, :insert)

  {:noreply, assign(socket, changeset: changeset)}
end
2 Likes

Thanks, this worked perfectly.

Can I make this validation be done only once?

Maybe you could put a conditional wrapper around the validation which is tied to a boolean in assigns? Like:

def mount(_params, _session, socket) do
  {:ok,
   socket |> assign(..., validation_already_done: false)}
end

def handle_event("validate", %{"mystruct" => params}, socket) do
  if socket.assigns.validation_already_done do
    {:noreply, socket}
  else
    # Current event handling logic

    {:noreply, assign(socket, validation_already_done: true, changeset: changeset)}
  end
end