简体   繁体   中英

javascript function inside jquery foreach loop doesn't wait for response

My foreach loop:

jQuery(".custom-checkbox").each(function() {
      if (jQuery(this).attr('data-action') == 'true') {

      if(deleteQuoteItemFromListing(jQuery(this).attr('data-id'))){
                    console.log('passed');
            }else{
                    console.log('failed');
            }
      }    
 });

And the function is(It's using prototype) but it successes

function deleteQuoteItemFromListing(id){
    //does someoperations and on success
    delurl = getDelUrl()+id; //baseurl/module/action/delete/id
    new Ajax.Request(delurl,{
        method: 'get',
        onSuccess: function(transport){
            return TRUE;
        } 
    })
}

but the problem is all foreach executes at once, and doesn't wait for response from function. It prints failed even the operation is success.

Updated

The other way round i tried first is this

jQuery('.delete-from-quote').click(function() {
        var i = 0, j = 0;
        jQuery(".custom-checkbox").each(function() {
            if (jQuery(this).attr('data-action') == 'true') {
                i++;
            }
        });


        if (i == 0) {
            alert('please choose product');
            return false;
        }

        jQuery(".custom-checkbox").each(function() {

            if (jQuery(this).attr('data-action') == 'true') {

                var urlData = "<?php echo $this->getUrl('qquoteadv/index/delete/'); ?>";
                urlData += "id/" + jQuery(this).attr('data-id') + "/"

                var ajax = jQuery.ajax({
                    type: "GET",
                    url: urlData,
                    success: function(msg) {
                        j++;
                    }
                })

            }
          if(i==j){location.reload();} //after completing all, reload the page
        });
  });

The problem is to know all action completed and reloading the page.

My guess is that the code you've omitted is doing an asynchronous ajax call. Since ajax is asynchronous by default, the code you write there ( $.ajax or whatever) starts the process, but then the process continues in the background while your code continues to run.

There's no reasonable way to make the deleteQuoteItemFromListing function wait for the response. (While it's possible to do synchronous ajax, A) it makes for a poor user experience by locking up the browser UI, and B) jQuery will be removing that option at some stage, forcing you to go direct to XHR if you want to keep doing it.)

Instead, restructure your code to embrace the asynchronous nature of web programming by having your function either return a promise or accept a callback, and then resolve the promise or call the callback when done.

Here's a rough idea of what the promise version would look like:

jQuery(".custom-checkbox").each(function() {
    if (jQuery(this).attr('data-action') == 'true') {
        deleteQuoteItemFromListing(jQuery(this).attr('data-id'))
            .done(function(id) {
                console.log(id + ' passed');
            })
            .fail(function(id) {
                console.log(id + ' failed');
            });
    }    
});

function deleteQuoteItemFromListing(id){
    var d = jQuery.Deferred();
    jQuery.ajax(/*...*/)
        .done(function() {      // This bit assumes the deletion worked if
            d.resolveWith(id);  // the ajax call worked, and failed if the
        })                      // ajax call failed; if instead the ajax
        .fail(function() {      // call always works and returns a flag,
            d.rejectWith(id);   // adjust accordingly
        });
    return d.promise();
}

Using callback ensures that the function is executed.

jQuery(".custom-checkbox").each(function () {
    if (jQuery(this).attr('data-action') == 'true') {
        deleteQuoteItemFromListing(jQuery(this).attr('data-id'), handleData);

    }
});

    function handleData(data) {
    if (data) {
        console.log('passed');
    } else {
        console.log('failed');
    }
}


function deleteQuoteItemFromListing(id, callback) {
    //does someoperations and on success
    delurl = getDelUrl() + id; //baseurl/module/action/delete/id
    new Ajax.Request(delurl, {
        method: 'get',
        onSuccess: function (transport) {
            callback(true);
        }
    })
}

I hope this will work for you. you need to define handleData function outside of the other function.

(Part of) Your problem is in this simple statement:

return TRUE;

In JavaScript, the "true" boolean is written in lowercase:

return true;

The interpreter thinks TRUE is a variable, and will throw a ReferenceError , since it's not set / defined anywhere, meaning the function will never return true .

Use jquery When.

You need to queue those Deferred in an array of Deferred and then apply all of the functions at once.

If one fails all will fail and if all succeeds all will pass.

check this out jQuery When

      var queue = [];
      var items = 0;
      return new $.Deferred(function (deferred) {
      $(".custom-checkbox").each(function () {
       if ($(this).attr('data-action') == 'true') {
        items++;
        queue.push(function () {
            new Ajax.Request(delurl, {
                method: 'get',
                onSuccess: function (transport) {
                    items--;
                    if(items === 0)
                        deferred.resolve();
                },
                onError:function(e){
                  deferred.reject(e);   
                }
            });
        });
    }
});

//now resolve all of the deferred fns

  $.when(queue).done(function(){
      console.log('All went well');
  })
 .fail(function(e){
      console.log('Error ' + e);
  });
});      

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM