1

Is it possible to make this loop wait until the AJAX call has finished before moving onto the next iteration?

for(curr;curr < total;curr++) {
    $this.val('Uploading '+(curr+1)+' out of '+total);
    var tmpStr = JSON.stringify(o[curr]).replace("&", "and");
    tmp[0] = JSON.parse(tmpStr);

    $.ajax({
        type: 'POST',
        url: 'http://example.com/api/post',
        data: "data="+JSON.stringify(tmp),
        success: function(msg) {

            var d = JSON.parse(msg);
            if (d.success) {

                //localStorage.removeItem("data");
            }
            else
            {
                alert("Data failed to upload, please try again");
            }
        },
        error: function(msg) {
            alert("Data failed to upload, please try again");
            $this.val('Upload to CMS');
        }
    });
}
TMH
  • 6,096
  • 7
  • 51
  • 88
  • 2
    Pedantically, no. It's not **a** jax if it's synchronous, but I'd suggest you refactor your code rather than make it synchronous – Paul S. May 19 '14 at 14:14

2 Answers2

2

You can use the when keyword with a recursive function. The when keyword allows you to wait for ajax calls. After an ajax call, when function sends the result to done function even it fails. You can expand your scenario by adding some error control into your ajax call. But I am giving this example:

function reCursive(curr,total)
{
    if(curr < total) 
    {
        $this.val('Uploading '+(curr+1)+' out of '+total);
        var tmpStr = JSON.stringify(o[curr]).replace("&", "and");
        tmp[0] = JSON.parse(tmpStr);

        $.when(function() 
        {
            return $.ajax(
            {
                type: 'POST',
                url: 'http://mvc.sivapi.sheffieldnetwork.com/form/submit/submit/meadowhallEaster/',
                data: "data="+JSON.stringify(tmp),
                success: function(msg) 
                {
                    var d = JSON.parse(msg);
                    if (d.success) 
                    {
                        //localStorage.removeItem("data");
                    }
                    else
                    {
                        alert("Data failed to upload, please try again");
                    }
                },
                error: function(msg) 
                {
                    alert("Data failed to upload, please try again");
                    $this.val('Upload to CMS');
                }
            });
        }).done(function (x) 
        {
            //When you get the result from your ajax call. Write your code here.
            curr++;
            reCursive(curr, total);
        });
    }
}
Bura Chuhadar
  • 3,653
  • 1
  • 14
  • 17
2

While you can't make the loop for loop wait, you can rewrite the code to use another style of invocation to run.

function runOnce(curr) {
  $this.val('Uploading ' + (curr + 1) + ' out of ' + total);
  var tmpStr = JSON.stringify(o[curr]).replace("&", "and");
  tmp[0] = JSON.parse(tmpStr);

  $.ajax({
    type: 'POST',
    url: 'http://mvc.sivapi.sheffieldnetwork.com/form/submit/submit/meadowhallEaster/',
    data: "data=" + JSON.stringify(tmp),

    // ***ADDED HERE*
    always: {
      if (curr < total) {
        runOnce(curr+1);
      } else {
        alert("All done-- you could call your next function from here.");
      }
    },
    success: function (msg) {

      var d = JSON.parse(msg);
      if (d.success) {
        //localStorage.removeItem("data");
      } else {
        alert("Data failed to upload, please try again");
      }
    },
    error: function (msg) {
      alert("Data failed to upload, please try again");
      $this.val('Upload to CMS');
    }
  });
}

// Set things up and run it once.
// The '0' is what the loop index would be.
runOnce(0);
Jeremy J Starcher
  • 23,369
  • 6
  • 54
  • 74
  • Recursion for the win – Jon P May 19 '14 at 14:22
  • @JonP - Technically, this is *not* recursion because there is only one instance of `runOnce` on the stack... – Jeremy J Starcher May 19 '14 at 14:23
  • Getting side tracked, but doesn't the fact the function calls itself as part of the `always` condition make it recursion... or is there some subtlety I'm missing out on? – Jon P May 19 '14 at 14:26
  • 1
    @JonP - Yes, there is a subtle difference. In recursion the original function hangs around so you can `return` a value to it and you have as many instances of the function on the stack as you do invocations. In this case, the function is simply being re-invoked by an event (`always` in this case.) There is only *one* copy of `runOnce` on the stack at a time. – Jeremy J Starcher May 19 '14 at 14:32