skip to Main Content

I’m trying to figure why/how can I make the button text update before the "each" loop, so I can provide feedback to the users while it’s running… but it only seems to update after the "each" has completed.

In my example, the button will go "Updating please wait…" after the each has run. So if it take 10s, the button stay enable and with the text "Update" (original value). I want it to be disable and display "Updating please wait …" while the Loop (each) is running.

Got an idea why?

  $("#UpdateRFID").click(function() {
    $('#UpdateRFID').prop("disabled", true).prop("value", "Updating please wait...");
    UpdateRFID();
    //$('#UpdateRFID').prop("disabled", false).prop("value", "Update");
  });

  function UpdateRFID() {
    $('.skurow[submitted="0"]').each(function() {
      sku = $(this).attr('sku');
      $.ajax({
        url: 'class.action.php',
        type: 'post',
        async: false,
        dataType: 'JSON',
        data: {
          "action": "GetDataFromTagID",
          "tagid": sku
        },
        success: function(response) {
          console.log('ok');
        },
        error: function(response) {
          console.log(response.responseText);
        }
      });
    });
  }

Button :

<input class="MenuButton" name="UpdateRFID" id="UpdateRFID" value="Update" type="button" />

Here’s another test I did. In this Example, when I click the button, I get an alert "Start", then it wait for about 3 secondes (sleep in the PHP Code for testing), then I get the alert "Done", then the button is disable and change to "Recherche …". I’m not sure why… I want it to be disable before the "each" start.

  function UpdateRFID() {
    $("#UpdateRFID").prop("disabled", true).prop("value", "Recherche ...");
    alert("Start");

    $('.skurow[submitted="0"]').each(function () {
      sku = $(this).attr("sku");
      $.ajax({
        url: "class.action.php",
        type: "post",
        async: false,
        dataType: "JSON",
        data: {
          action: "GetDataFromTagID",
          tagid: sku,
        },
        success: function (response) {
          console.log("ok");
        },
        error: function (response) {
          console.log(response.responseText);
        },
      });
    });

    alert("Done");
    //$('#UpdateRFID').prop("disabled", false).prop("value", "Mise a jour nom RFID");
  }

Here’s the full code standalone code to reproduce the problem:
jQuery is 2.2.1
PHP is 5.4 (but I don’t think it’s relevant)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="includes/jquery.min.js"></script>
    <title>Document</title>
</head>

<body>

    <p class="ScanText">SKU</p> <input class="FullSizeBox" type="text" id="SKU" name="SKU" onclick="BoxSelect(this.id);" />
    <script type="text/javascript">
        $('#SKU').focus();
    </script>

    <br><input class="MenuButton" name="UpdateRFID" id="UpdateRFID" value="Mise a jour nom RFID" type="button" />

    <div id="qtsku" style="margin-left:5px">-</div>

    <div id="divSKUScanned">
        <table id="ScannedSKU">
            <thead>
                <tr>
                    <th></th>
                    <th></th>
                </tr>
            </thead>
            <tbody>
                <!-- updated by JavaScript -->
            </tbody>
        </table>

    </div>

    <div class="ScanSubmit"><input class="MenuButton" id="btnsubmit" type="button" value="Soumettre" onclick="SubmitVE();" disabled></div>

    <script>
        function SkuCount() {
            skucount = $('#ScannedSKU tr').length - 1;
            stritem = 'item';
            if (skucount > 1) {
                stritem = 'items';
            }
            $('#qtsku').html('Total ' + stritem + ': ' + skucount);
            if (skucount == 0) {
                $('#qtsku').html('');
            }
        }
        SkuCount();

        $(document.body).on('click', '.delButton', function() {
            sku = $(this).closest("tr").find('.skudesc').text();
            r = confirm('Effacer ' + sku + ' ?');
            if (r == true) {
                $(this).closest("tr").remove();
            }
            SkuCount();
            $('#SKU').focus(); //TODO: That Focus dosent work...
        });

        $('#SKU').keypress(function(event) {
            keycode = (event.keyCode ? event.keyCode : event.which);
            if (keycode == '13') {
                sku = this.value;
                sku.trim();
                this.value = "";
                if (sku != "") {
                    if (!($('.skurow[sku="' + sku + '"').length)) {
                        delBtn = '<input name="delButton" id="delButton" class="delButton" type="button" value="X" style="background-color:gray; color:black">';
                        $('#ScannedSKU > tbody:last-child').append('<tr class="skurow" submitted="0" sku="' + sku + '"><td class="delbtn">' + delBtn + '</td><td class="skudesc">' + sku + '</td></tr>');
                        $("#btnsubmit").prop("disabled", true);
                        SkuCount();
                    }
                }
            }
        });

        $("#UpdateRFID").click(function() {
            UpdateRFID();
        });

        function UpdateRFID() {
            $('#UpdateRFID').prop("disabled", true).prop("value", "Recherche ...");
            alert('Start');

            $('.skurow[submitted="0"]').each(function() {
                sku = $(this).attr('sku');
                $.ajax({
                    url: 'class.action.php',
                    type: 'post',
                    async: false,
                    dataType: 'JSON',
                    data: {
                        "action": "GetDataFromTagID",
                        "tagid": sku
                    },
                    success: function(response) {
                        console.log('ok');
                    },
                    error: function(response) {
                        console.log(response.responseText);
                    }
                });
            });

            alert('Done');
            //$('#UpdateRFID').prop("disabled", false).prop("value", "Mise a jour nom RFID");
        }
    </script>


</body>

</html>

and this is the php page section for class.action.php

<?php
if ($_POST["action"] == "GetDataFromTagID") {
sleep(3);
}
?>

3

Answers


  1. Chosen as BEST ANSWER

    Update #4 : Patched This is working, but the final solution is in the Update #5.

    Thanks to @freedomn-m , I only added a little timeout and it fixed it. Wish I could do "update the button then do this", but if it's working like this, I'm OK with it!

     $("#UpdateRFID").click(function() {
        $('#UpdateRFID').prop("disabled", true).prop("value", "Recherche ...");
        setTimeout(UpdateRFID, 100);
      });
    

    Note that setTimeout(UpdateRFID(), 100); dosent work. Not sure why.


  2. What you have may work; or may not over time.

    What you should do is use a Promise and after all the loop and ajax is done you can resolve that.

    This is not a tested solution nor is this super solid. I did add a few things like how to enable and disable the button based on a custom event trigger, how to wrap the Promise in the function UpdateRFID etc.

    I removed onclick="BoxSelect(this.id);" because seeing a click on a text input is just weird and it did not exist in the code; And, you can add a click handler in the JavaScript code (better) with $('#SKU').on('click',function(){BoxSelect(this.id);});

    I do see a lot of other things I would probably change but just the Promise is what you need to focus on here.

    $('#SKU').focus();
    
    function SkuCount() {
      let skucount = $('#ScannedSKU').find('.skurow').length - 1;
      let stritem = 'item' + !!skucount ? 's' : '';
      let updateText = skucount == 0 ? '' : 'Total ' + stritem + ': ' + skucount;
      $('#qtsku').html(updateText);
    }
    
    $('#ScannedSKU').on('click', '.delButton', function() {
      let sku = $(this).closest("tr").find('.skudesc').text();
      let r = confirm('Effacer ' + sku + ' ?');
      if (!!r) {
        $(this).closest("tr").remove();
      }
      SkuCount();
      $('#SKU').focus();
    });
    
    $(document.body).on('keypress', function(event) {
      let keycode = event.keyCode ? event.keyCode : event.which;
      if (keycode == '13') {
        const skuContainer = $('#ScannedSKU').find('.sku-container');
        const skuList = skuContainer.find('.skurow');
        let sku = this.value.trim(); //?????
        this.value = "";
        if (!!sku && !skuList.filter('[data-sku="' + sku + '"]').length) {
          let newtr = $('#newrows').find('.skurow').first().clone();
          newtr.data('sku', sku);
          newtr.find('skudesc').html(skudesc);
          skuContainer.append(newtr);
          $("#btnsubmit").prop("disabled", true);
          SkuCount();
        }
      }
    });
    
    function UpdateRFID() {
      $('#UpdateRFID').trigger("disable-me");
      alert('Start');
      const myPromise = new Promise((resolve, reject) => {
        $('.skurow[submitted="0"]')
          .each(function() {
            let sku = $(this).data('sku');
            const skuData = {
              "action": "GetDataFromTagID",
              "tagid": sku
            };
            $.ajax({
                url: 'class.action.php',
                type: 'post',
                dataType: 'JSON',
                data: skuData
              })
              .done(function(response) {
                console.log('ok');
              })
              .fail(function(response) {
                console.log(response.responseText);
              });
          });
        resolve("looperdone");
      });
    
      myPromise
        .then(function() {
          alert('Done');
        })
        .then(function() {
          $('#UpdateRFID').trigger("enable-me");
        });
    }
    
    // this was missing so this is just an empty function
    function SubmitVE() {}
    $('#btnsubmit').on('click', SubmitVE);
    
    $("#UpdateRFID")
      .on('click', UpdateRFID)
      .on('enable-me', function() {
        $(this).prop("disabled", false).prop("value", "Mise a jour nom RFID");
      }).on('disable-me', function() {
        $(this).prop("disabled", true).prop("value", "Recherche ...");
      });
    
    SkuCount();
    .delButton {
      background-color: gray;
      color: black;
    }
    
    .element-container {
      display: none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <p class="ScanText">SKU</p>
    <input class="FullSizeBox" type="text" id="SKU" name="SKU" />
    <input class="MenuButton" name="UpdateRFID" id="UpdateRFID" value="Mise a jour nom RFID" type="button" />
    <div id="qtsku" style="margin-left:5px">-</div>
    <div id="divSKUScanned">
      <table id="ScannedSKU">
        <thead>
          <tr>
            <th></th>
            <th></th>
          </tr>
        </thead>
        <tbody class='sku-container'>
          <!-- updated by JavaScript -->
        </tbody>
      </table>
    </div>
    <div class="ScanSubmit"><input class="MenuButton" id="btnsubmit" type="button" value="Soumettre" disabled></div>
    
    <div class="element-container">
      <table id="newrows">
        <tbody>
          <tr class="skurow" submitted="0" sku="">
            <td class="delbtn"><button name="delButton" class="delButton" type="button">X</button></td>
            <td class="skudesc"></td>
          </tr>
          <tbody>
      </table>
    </div>
    Login or Signup to reply.
  3. Update #5 : SOLVED

    This is how my final code is. I manage to use the function $.when to run all my ajax request and then do actions. Now my button update correctly and I also manage to get ride of the async: false that is way better. My page update evertime an "ajax" call is resolved and at the end of all ajax call (done or fail), I re-enable the button.

    Thanks for all the help here. Helped me to go into the right direction! 🙂

    function UpdateRFID() {
        $('#UpdateRFID').trigger("disable-me");
    
        const UpdateRFIDajaxes = [];
    
        $('.skurow[submitted="0"]')
          .each(function() {
            sku = $(this).attr('sku');
            const skuData = {
              "action": "GetDataFromTagID",
              "tagid": sku
            };
            UpdateRFIDajaxes.push(
              $.ajax({
                url: 'class.action.php',
                type: 'post',
                dataType: 'JSON',
                data: skuData
              })
              .done(function(response) {
                //do ok stuff.
               console.log('ok')
              })
              .fail(function(response) {
                //do failed stuff.
                console.log('failed');
              })
            );
          });
        $.when.apply($, UpdateRFIDajaxes)
          .always(function() {
            $('#UpdateRFID').trigger("enable-me");
            EnableSubmit();
            $('#SKU').focus();
          }).done(function() {
            //console.log('Done.');
          })
          .fail(function() {
            alert('Erreur, ca ne fonctionne pas, etes vous sur le WiFi?');
          });
      }
    
    
      $("#UpdateRFID")
        .on('click', function() {
          UpdateRFID();
        })
        .on('enable-me', function() {
          $(this).prop("disabled", false).prop("value", "Mise a jour nom RFID");
        }).on('disable-me', function() {
          $(this).prop("disabled", true).prop("value", "Recherche ...");
        });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search