1

I'm trying to execute a callback after multiple jQuery Ajax have completed.
In my code both Ajax requests call another function and when I try to use these functions I get undefined.
I think the problem has to do with using deferred/promise, but I don't know how to use them.

Here is my code:

<link rel="stylesheet" type="text/css" href="https://tag/sites/ocean1/maker/captions/shared%20documents/Web_ComplianceCSS.txt">
<div id = "cabbage" style="font-size:10px">
  <p>Web Compliance Stats</p>
</div>
<script type = "text/javascript">
  var WebComplianceReportApp = {} || WebComplianceReportApp;
  WebComplianceReportApp.GetStatuses = (function() {
    var pub = {},
      _userId,
      _ultimateObjectHolderArr = [],
      _items = [],
      _options = {
        listName: "M_Web_Compliance",
        container: "#cabbage",
      };
    pub.init = function() {
      var clientContext = new SP.ClientContext.get_current();
      _userId = clientContext.get_web().get_currentUser();
      clientContext.load(_userId);
      clientContext.executeQueryAsync(getUserInfo, _onQueryFailed);
    };

    function getUserInfo() {
      _userId = _userId.get_id();
      getSpecifiedList(_options.listName, _userId);
    }

    function buildObject(results, listName) {
      _items = results.d.results;
      $.each(_items, function(index, item) {
        _ultimateObjectHolderArr.push({
          "Division": item.ParentOrg,
          "ORG": item.ORG,
          "URL": item.URL,
          "Status": item.Site_Status
        });
      });
      //createStatusView2(_ultimateObjectHolderArr);
    }

    function getSpecifiedList(listName, userId) {
      var counter = 0;
      var baseUrl = SP.PageContextInfo.get_webServerRelativeUrl() + "/_vti_bin/listdata.svc/" + listName;
      var url1 = baseUrl + "?$select=ParentOrg,ORG,URL,Site_Status&$inlinecount=allpages";
      var call1 = $.ajax({
        url: url1,
        type: "GET",
        headers: {
          "accept": "application/json;odata=verbose",
        }
      }).done(function(results) {
        buildObject(results, listName);
      }).fail(function(error) {
        console.log("Error in getting List: " + listName);
        $(_options.container).html("Error retrieving your " + listName + ". " + SP.PageContextInfo.get_webServerRelativeUrl());
      });
      var url2 = baseUrl + "?$select=ParentOrg,ORG,URL,Site_Status&$inlinecount=allpages&$skiptoken=1000";
      var call2 = $.ajax({
        url: url2,
        type: "GET",
        headers: {
          "accept": "application/json;odata=verbose",
        }
      }).done(function(results) {
        buildObject(results, listName);
      }).fail(function(error) {
        console.log("Error in getting List: " + listName);
        $(_options.container).html("Error retrieving your " + listName + ". " + SP.PageContextInfo.get_webServerRelativeUrl());
      });
    }

    function createStatusView2(Arr) {
        var divisionArr = [];
        var oRGArr = [];
        var divisionCount = 0;
        var oRGCount = 0;
        for (var i = 0; i < Arr.length; i++) {
          if ($.inArray(Arr[i].Division, divisionArr) === -1) {
            divisionArr.push(Arr[i].Division);
            var divisionHolderElement = $("<div id='p_" + Arr[i].Division + "' class='division_row_holder'></div>");
            var divisionElement = $("<div id='" + Arr[i].Division + "' class='division_div ORG'></div>").text(Arr[i].Division);
            $("#cabbage").append(divisionHolderElement);
            $(divisionHolderElement).append(divisionElement);
          }
          if ($.inArray(Arr[i].ORG, oRGArr) === -1) {
            oRGArr.push(Arr[i].ORG);
            var orgElement = $("<div class='org_div ORG' id='" + Arr[i].ORG + "' style='font-size:10px;'></div>").text(Arr[i].ORG);
            $("#p_" + Arr[i].Division).append(orgElement);
          }
        }
      }
    //automatically fired by init
    function _onQueryFailed(sender, args) {
      alert('Request failed.\nError: ' + args.get_message() + '\nStackTrace: ' + args.get_stackTrace());
    }
    return pub
  }());
  $(document).ready(function() {
    SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function() {
      //After the SP scripts are run, we access the WebComplianceReportApp.GetStatuses
      WebComplianceReportApp.GetStatuses.init();
    });
  });
</script>
M_66
  • 299
  • 5
  • 19

3 Answers3

1

I dont know if this will make your code dirty, but I would use a flag in this case

ex:

var ajaxCalls = 0;
function checkAjaxCalls()
{
   if (ajaxCalls == 2)
   {
    //do your thing...
    //and maybe you want to reset ajaxCalls value to zero if needed...
   }
}

And from each Ajax response completes, increment ajaxCalls variable by one, and call the checkAjaxCalls function from both your Ajax responses.

sameh.q
  • 1,691
  • 2
  • 23
  • 48
0

You could call createStatusView(); and then call createStatusView2(); after all of your Ajax requests are done

$(document).ready(function(){
  createStatusView();
  $(this).ajaxStop(function() {
    // NOTE: I did not see you use createStatusView(); in your code
    createStatusView2();
  });
});
Anderson
  • 1
  • 3
  • I have two separate AJAX jQuery calls within a function **getSpecifiedList(listName, userId)** . After each AJAX call, I use done to call **buildObject()**, so that is 2 times. I only want the **createStatusView()** to run 1 time, after both AJAX calls complete the **buildObject()** function. So, the solution you recommended doesn't work at this time. Am I missing something in your response? – M_66 Apr 02 '16 at 16:20
0

Method One:

This time we'll have waited for the request to complete instead of waiting for the request to succeed

$(".ajax-form-button-thingy").on("click", function() {
  $.ajax({
    url: $(this).attr("href"),
    type: 'GET',
    error: function() {
      throw new Error("Oh no, something went wrong :(");
    },
    complete: function(response) {
      $(".ajax-form-response-place").html(response);
    }
  });
});

Method Two:

If you want to wait for ALL Ajax requests to complete without changing the async option to false then you might be looking for jQuery.ajaxComplete();

In jQuery every time an Ajax request completes the jQuery.ajaxComplete(); event is triggered.

Here is a simple example but there is more info on jQuery.ajaxComplete(); over here.

$(document).ajaxComplete(function(event, request, settings) {
  $(".message").html("<div class='alert alert-info'>Request Complete.</div>");
});


Also you can take a look at the Ajax response by using request.responseText this might be useful in case you want to double check the response.

For more information about jQuery.ajax you can read the docs here

  • You should never ever set the `async` option to `false`. – Bergi Apr 02 '16 at 16:47
  • Is there a bug, problem or issue I don't know about or is that purely opinion based? –  Apr 02 '16 at 16:48
  • It's effectively deprecated. And hangs the UI. You always want your networking operations be asynchronous. – Bergi Apr 02 '16 at 16:48
  • I have removed the ```async``` option from my answer but I still want to understand more on this could you lead me to a article on this? –  Apr 02 '16 at 16:52
  • 2
    http://stackoverflow.com/questions/11448011/jquery-ajax-methods-async-option-deprecated-what-now, https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests – Bergi Apr 02 '16 at 16:55
  • @Bergi thanks for letting me know about this, appreciate it. –  Apr 02 '16 at 17:01