twan
twan

Reputation: 2659

How to make sure a button is disabled until an ajax request is 100% finished

I've got a function that refreshes some json when a plus or a minus button is clicked. Below is a big button that I disable until the refresh is done.

Currently I do it like this:

My refresh function:

function refreshform(force, element, orderline){
    $.ajax({
     type:'post',
     url:"payprocess/refreshform.php",
     data:({orderline:orderline}),
     success:function(data){
         $(element).empty().append( data );
     }
 });
}

My plus minus button functions:

$('.pluscheckout').click(function(e) {
    e.preventDefault();
    var $button = $(this).prop('disabled', true);
    var $input = $(this).closest('.quantitybtns').siblings('.aantal');
    var productid = $(this).closest('.quantitybtns').siblings('.productid').val();
    var $pricediv = $(this).closest('.prodinfoquantity').siblings('.prodinfoprice');
    var thiselement = $(this).closest('.productblocktop').siblings('.orderlineloop').find('.editorform');
    var orderline = $(this).closest('.productblocktop').siblings('.orderlineloop').find('.refreshform').attr('id');
    var $uploadbtn = $(this).closest('.productblocktop').siblings('.orderlineloop').find('.uploadbtn');
    $uploadbtn.prop('disabled', true);
    $uploadbtn.addClass('disabledbtn');
    var currentValue = parseInt($input.val());
    var quantity = parseInt($input.val()) + 1;
    $input.val(currentValue + 1);
    $.ajax({
        type: 'post',
        url: "checkout/prices.php",
        data: ({ quantity: quantity, productid: productid }),
        success: function(data) {
            $($pricediv).empty().append( data );
        },
        complete: function(data) {
            refreshform(true, thiselement, orderline);
            $button.prop('disabled', false);
            $uploadbtn.prop('disabled', false);
            $uploadbtn.removeClass('disabledbtn');
        }
    });
});

$('.mincheckout').click(function(e) {
    e.preventDefault();
    var $button = $(this).prop('disabled', true);
    var $input = $(this).closest('.quantitybtns').siblings('.aantal');
    var productid = $(this).closest('.quantitybtns').siblings('.productid').val();
    var $pricediv = $(this).closest('.prodinfoquantity').siblings('.prodinfoprice');
    var thiselement = $(this).closest('.productblocktop').siblings('.orderlineloop').find('.editorform');
    var orderline = $(this).closest('.productblocktop').siblings('.orderlineloop').find('.refreshform').attr('id');
    var $uploadbtn = $(this).closest('.productblocktop').siblings('.orderlineloop').find('.uploadbtn');
    var currentValue = parseInt($input.val());
    var quantity = parseInt($input.val()) - 1;
    if(quantity > 0){
        $uploadbtn.prop('disabled', true);
        $uploadbtn.addClass('disabledbtn');
        $input.val(currentValue - 1);
        $.ajax({
         type:'post',
         url:"checkout/prices.php",
         data:({quantity: quantity, productid: productid}),
         success:function(data){
             $($pricediv).empty().append( data );
             couponpost(true, 'true');
         },
        complete: function(data) {
            refreshform(true, thiselement, orderline);
            $button.prop('disabled', false);
            $uploadbtn.prop('disabled', false);
            $uploadbtn.removeClass('disabledbtn');
        }
     });
 }else{
     $button.prop('disabled', false);
 }
});

$uploadbtn is the button that needs to be disabled until the ajax call has completed. So when clicking either the plus or minus button, I disable the button and enable it again in the complete of the ajax call.

But for some strange reason, the button becomes active again while refreshform is still running. If I spam click plus or minus, I can see the button become active and after that the result of refreshform is still refreshing.

I made a video to show what I mean:

https://streamable.com/2wzkah

I thought maybe I should add a complete in my refreshform function like this:

function refreshform(force, element, orderline){
    $.ajax({
     type:'post',
     url:"payprocess/refreshform.php",
     data:({orderline:orderline}),
     success:function(data){

     },
     complete: function() {
        $(element).empty().append( data );
     }
 });
}

But with that code the following line stops working: $(element).empty().append( data );. $(element) is empty.

How can I fix this?

The button needs to be disabled until the quantity from the json matches the quantity in the input field. Don't worry I check for the rest also on the server side.

HTML:

<div class="productblock">
    <div class="productblocktop">
        <div class="prodinfoleft">
            <img class="previewprodthumb" src="cms/images/producten/textiel_producten/textielwand/1288_9936468fbe050be8_1.jpg" alt="" onerror="this.src='assets/images/custom/noimgprint.jpg'" />
            <div class="">
                <a href="https://printzelf.nl/textiel/textielframe"><h4>Textielframe</h4></a>

                <ul class="refreshspecs">
                    <a href="javascript:void(0);" id="togglespecscheckout" class="prodinfocheckout">Specificaties <i class="fas fa-chevron-down"></i></a>
                    <span class="speclist">
                        <li>Hoogte : 90cm</li>
                        <li>Breedte : 90cm</li>
                        <li>Samenstellling : Frame</li>
                        <li>Frame : Met LED verlichting</li>
                        <li>Ontwerp : PRO ontwerpcontrole</li>
                    </span>
                </ul>

                <form class="controleopties">
                    <span class="controltip" aria-expanded="false">
                        <label>
                            <input type="radio" value="basis" name="ontwerpcontrole" />
                            <span>AUTO ontwerpcontrole - Gratis</span>
                        </label>
                    </span>

                    <span class="controltip1" aria-expanded="false">
                        <label>
                            <input type="radio" value="pro" name="ontwerpcontrole" checked="" />
                            <span>PRO ontwerpcontrole - € 9,-</span>
                        </label>
                    </span>
                </form>
            </div>
        </div>
        <div class="prodinforight">
            <div class="prodinfoquantity">
                <input class="productid" type="hidden" name="productid" value="60eea4b1a615d" />
                <input type="number" class="form-control aantal" value="39" min="1" />
                <div class="quantitybtns">
                    <button class="mincheckout">−</button>
                    <button class="pluscheckout">+</button>
                </div>
            </div>
            <div class="prodinfoprice">
                <span><b>€ 8.188,91</b></span>
            </div>
        </div>
        <div class="actionbtns">
            <span class="orderlinetip" aria-expanded="false">
                <a href="javascript:void(0);" class="deleteproduct" id="60eea4b1a615d"><i class="icon-trash"></i></a>
            </span>
        </div>
    </div>
    <span class="orderlineloop">
        <input type="hidden" class="order_id_input" value="59.1495" />
        <input type="hidden" class="orderline_id_input" value="60eea4b1a615d" />
        <span class="refreshform" id="60eea4b1a615d">
            <form class="editorform" method="post" target="_blank">
                <input
                    type="hidden"
                    name="json"
                    value='{"customer_id":"59","order_id":"59.1495","quantity":"39","rulers":"cm","canvas_size":"900x900","bleed":"","safety_margin":"","dpi":50,"procheck":"y","multiple_pages":"1","product_name":"Textielframe","product_thumbnail":"https:\/\/printzelf.nl\/cms\/images\/producten\/textiel_producten\/textielwand\/1288_9936468fbe050be8_1.jpg","orderline":"60eea4b1a615d"}'
                />
            </form>
        </span>

        <div class="productblockbottom">
            <span>
                <b>Hoe lever je jouw ontwerp aan?</b>
                <span class="tooltippy_nostyle" aria-expanded="false">
                    <img class="infosvg" src="assets/images/custom/icon_info.svg" />
                </span>
            </span>
            <div class="productblockbtns">
                <a href="javascript:void(0);">
                    <button class="btnstyle uploadbtn gapfixbtn" type="button" name="button"><span>Lever je bestanden aan</span> <i class="icon-upload"></i></button>
                </a>
            </div>
        </div>
        <span class="unfinished editstatuscheck"></span>
    </span>
</div>

Upvotes: 1

Views: 552

Answers (1)

Rory McCrossan
Rory McCrossan

Reputation: 337560

You can achieve this by returning the jqXHR object from the $.ajax() call in refreshForm(). You can then perform the actions on the buttons when the promise in that object is resolved. Try this:

function refreshform(force, element, orderline) {
  return $.ajax({
    type: 'post',
    url: "payprocess/refreshform.php",
    data: { orderline: orderline }, // note: parentheses not needed here
    success: function(data) {
      $(element).empty().append(data);
    }
  });
}

// inside the complete handler:
complete: function(data) {
  refreshform(true, thiselement, orderline).then(() => {
    $button.prop('disabled', false);
    $uploadbtn.prop('disabled', false);
    $uploadbtn.removeClass('disabledbtn');
  });
}

Upvotes: 1

Related Questions