How do I update the form inputs from the server side?

The Liveview document saids:

For any given input with focus, LiveView will never overwrite the input’s current value, even if it deviates from the server’s rendered updates.

However, I want to overwrite the input’s current value with the server side value. How do I achieve that? I want to make sure certain input fields in a form are force validated to approved value from the server side.

The chunk of docs you’re reading is about the input field that the user is currently typing into. If you have the value of an input set from an assign, simply change the value of the assign, and the value of the input will change.

What I observed is the following sequence:

  1. User change input A
  2. Which triggered phx-change and the server side also changed the assign that backs input A
  3. The client side value prevails

I understand that in phx-change handler, I can modify any other inputs. However, I want to be able to modify the focused input that triggered this phx-change too.

Have you ever worked with a self correcting input field while you edit it? Those are – besides some rare exceptions – a nightmare in terms of UX, even if completely client side driven. With LV this is even worse given the added latency.

I see your point. I am trying to auto-sort a list of user inputs, so I am not really changing them; only rearranging them as user typing them. I can sorta achieve this effect by setting '“phy-debounce”: “blur”` but it is still not exactly what I like.

Even rearranging while they’re typing is a pain, it’ll make using arrow keys a nightmare. I wouldn’t even do this with Javascript which can do this w/o latency, you add in the round trip to a server and this seems like it’d be a very problematic UX.

I had a similar problem while implementing a search box with autocomplete and dropdown selection. I wanted to:

  1. replace the user input in the search box whenever the user selects an entry from the dropdown and also trigger a phx-change event
  2. clear the input whenever the user clicks on the search box (or hit enter after giving it focus using the tab key).

Since in all of these situations the input has focus, I wasn’t able to do it completely from the server-side. What I ended up doing is pushing events to the JS frontend and doing the changes and triggering phx-change from there.

This are the code snippets for case (1)

Server:

# called when the user selects an element from the dropdown
push_event("selected", %{selected: [label, selected]})

Client:

 mounted() {
       this.handleEvent("selected", ({selected: [label, selected]}) => {
             this.setSearchInputValue(label);
             this.setHiddenInputValue(selected)
       })
}
setSearchInputValue(value) {
            this.el.querySelector("input[type=text]").value = value;
        },
setHiddenInputValue(value) {
          const hidden_input = this.el.querySelector("input[type=hidden]")
          hidden_input.value = value
          # this is to trigger the phx-change evenr
          hidden_input.dispatchEvent(new Event('input', {bubbles: true}))
 },

(the actual selected value is in a hidden input, the search box only contains the label)

5 Likes

I have a similar use case to this, I tried this but doesn’t work. Any idea why?

<%= hidden_input(@form, @field,
            name: "#{@form.name}[#{@field}][]",
            value: option,
            "phx-hook": "PublishInput"
          ) %>
Hooks.PublishInput = {
    updated() {
      this.el.dispatchEvent(
        new Event("input", {bubbles: true})
      )
    }
  }

let liveSocket = new LiveSocket("/live", Socket, { params: { _csrf_token: csrfToken }, hooks: Hooks })