Suppressing updates to an Input field while it's selected?

I’ve got a Phoenix LiveView that is updating part of its state every second.

I need to allow certain users to update a different part of the state at any point. I built this widget to do so:

<div class="tw-text-3xl tw-font-bold tw-relative tw-group">
  <.countdown_widget
    label="T‒0"
    duration={Timex.diff(@state._meta.now, @state.t0, :duration)}
  />
  <%= if {@is_director} do %>
    <div class="tw-absolute tw-top-[100%] tw-inset-x-0 tw-hidden group-hover:tw-block group-focus:tw-block tw-z-10" role="none">
      <form action="javascript:"><input
        type="datetime-local"
        name="t0"
        title="T‒0"
        value={Timex.format!(@state.t0, "%Y-%m-%dT%H:%M:%S", Timex.Format.DateTime.Formatters.Strftime)}
        phx-change={JS.push("set_t0")}
        step="1"
      /></form>
    </div>
  <% end %>
</div>

however, this doesn’t seem to work. On Chrome and Edge (which will be the only options in prod), the input field is reset to be empty every time @state._meta.now ticks.

Is there any way to freeze the input so it can’t be updated by the server while it’s selected by the user?

If I understand correctly, seems like you need phx-update="ignore" in a dynamic way - while phx-change is happening. :thinking:
I’m thinking, if you had a regular handle event for phx-change, maybe you could assign a value on change phx-update={if @is_typing, do: "ignore", else: "replace"} so it’s set to true and ref = Process.send_after(self(), :typing_idle, 1000) you store the reference of a process that will trigger a handle info which would put the boolean assign to false. Then on start of each change event you cancel it:

  if socket.assigns.ref do
    Process.cancel_timer(socket.assigns.typing_timeout_ref)
  end

Might work, haven’t tried it. :sweat_smile:

My bad. This while-focused update suppression is enabled by default, but works in Edge and Chrome only when the initial value field applied to the datetime input is valid. The formatting function I was originally using didn’t output correct results; fixing that made it start working.

I don’t understand this, I have no idea why that would break this, but Phoenix was apparently doing the right thing by default here.

1 Like