htmx icon indicating copy to clipboard operation
htmx copied to clipboard

An out-of-order refresh bring old data(?)

Open mamcx opened this issue 3 years ago • 6 comments

I have an issue with users with slow connections. They are updating invoices in their phones (android) and sometimes the values are lost or overwritten.

<input  type="text" id="discount" name="discount" inputmode="decimal" hx-post="" hx-trigger="keyup changed delay:2s" hx-swap="outerHTML" hx-target="#content" hx-select="#content">

So, this is the flow of actions:

  1. Enter a value like 23. It gets sent to the server
  2. Now remove it or change it (23.3). It gets sent to the server
  3. Sometimes it gets rewritten into 23
  4. Then the server has responded with 23 then 23.3

I attach a video of the issue: https://user-images.githubusercontent.com/238983/133696804-155505bd-600e-441d-9263-443b68b1d44c.mp4

mamcx avatar Sep 16 '21 23:09 mamcx

It looks like you have two elements making submissions and having requests in flight at the same time, and as they compete to update one or the other wins.

The way to synchronize the two is to move the event up the DOM to a single element that issues requests on behalf of both elements:

  <div hx-post="/whatever" hx-trigger="changed from:.watch" ... >
     ...
     <input class="watch" ...>
     ...
     <input class="watch" ...
     ...
 </div>

Now the outer div is responsible for issuing the request and will properly enqueue new updates from the user while an existing request is in flight, thus serializing them.

1cg avatar Sep 19 '21 16:09 1cg

Ok, this conflict with the other triggers:

When I put this into the form tag:

<form id="app" name="Form" method="POST" hx-trigger="keyup changed delay:2s from:.input">
    <content id='content'>
            <input  type="text" id="qty" name="qty" class="input" hx-post="" hx-swap="outerHTML" hx-target="#content" hx-select="#content">

            <input  type="text" id="discount" name="discount" class="input" hx-post="" hx-swap="outerHTML" hx-target="#content" hx-select="#content">
   </content>
</form>

It only requests when the input gets out of focus, instead of on key change like before. I try moving around to the parent but it not fire, it needs to stay in the input. So is not clear (to me) how all the options interact.

mamcx avatar Sep 20 '21 17:09 mamcx

I think the problem here is a subtle one with changed, which applies to the form rather than the target element in this case.

If you remove that, it should work.

Sorry for the delay on this.

1cg avatar Nov 02 '21 22:11 1cg

Not work with the change. Same behavior. I also with only changed but same.

P.D: Is possible to control this by js? I have problems with users because this is altering the input data and is a bad thing when invoicing...

mamcx avatar Nov 03 '21 16:11 mamcx

Also keyup changed delay:1s means the delay is applied to both events? Or could be the delay is only for the last?

P.D: Removing the delay make the problem more evident.

mamcx avatar Nov 03 '21 16:11 mamcx

Ok, after looking at the code and remembering I have reported this issue, I do this change:

        function handlePreservedElements(fragment) {
            forEach(findAll(fragment, '[hx-preserve], [data-hx-preserve]'), function (preservedElt) {
                var id = getAttributeValue(preservedElt, "id");
                var oldElt = getDocument().getElementById(id);
                if (oldElt != null) {
                    //preservedElt.parentNode.replaceChild(oldElt, preservedElt);
                    preservedElt.value =  oldElt.value;
                }
            });
        }

This keeps the value to be replaced and avoids "jump" out of focus. Maybe add an option to hx-preserve for values?

mamcx avatar Nov 03 '21 21:11 mamcx