Using SPServices with Datatables: Table loads before SPServices GetListItem call is finished running

sharepoint.stackexchange https://sharepoint.stackexchange.com/questions/222626

  •  29-12-2020
  •  | 
  •  

Question

I'm using DataTables to display data from a list. I'm providing the data to DataTables from a SPServices GetListItems call. I had everything working fine, but a recent modification I made to the code must have changed the timing of how things load, and now the DataTables table is loading before the data from GetListItems is ready.

I've been looking into jQuery Deferred objects and promises, and I see that SPService objects provide promises. I've tried implementing promises in multiple ways, but my function that loads the table continues to run before the data is ready.

It seems like the deferral is partially working. My console log output tells me that my LoadDataTableSupporting function is running after the SPservices call, but there's no data. I believe that the .then is triggering after the GetListItems is complete, but before the completefunc has finished iterating through all of the items in the list and storing them in the listData array. Is there a way to trigger another to function to run after the completefunc function has finished iterating through the list data? Is there some promise or event that is triggered once the completefunc is complete that I can use to trigger my LoadDataTableSupporting function?

var listData = [];

$().SPServices({
    operation: "GetListItems",
    async: false,
    listName: "SAS2",
    CAMLQuery: query,  
    CAMLViewFields: "<ViewFields><FieldRef Name='FileLeafRef' /><FieldRef Name='Control_x0020_Number1' /><FieldRef Name='Subject' /><FieldRef Name='Suspense1' /><FieldRef Name='Lead_x0020_Agency1' /><FieldRef Name='Lead_x0020_AO1' /><FieldRef Name='Coordination1' /><FieldRef Name='Staff_x0020_Status1' /><FieldRef Name='Staff_x0020_AO1' /><FieldRef Name='_x0046_or1' /></ViewFields>",
    completefunc: function (xData, Status) {    
        $(xData.responseXML).SPFilterNode("z:row").each(function() {    
            if(Status == "success")
            {
                console.log("SPServices success");

                var fileNameArray = ($(this).attr("ows_FileLeafRef")).split("#");
                var fileName = fileNameArray[1];

                var forValue;

                if($(this).attr("ows__x0046_or1"))
                {
                    forValue = $(this).attr("ows__x0046_or1");
                }
                else
                {
                    forValue = " ";
                }

                var subjectValue = $(this).attr("ows_Subject");
                var leadAgencyValue = $(this).attr("ows_Lead_x0020_Agency1");
                var leadAoValue = $(this).attr("ows_Lead_x0020_AO1");
                var coordinationValue = formatLineBreaks($(this).attr("ows_Coordination1"));
                var staffStatusValue = $(this).attr("ows_Staff_x0020_Status1");
                var staffAoValue = formatLineBreaks($(this).attr("ows_Staff_x0020_AO1"));

                var newRow = [generateDataViewURL(fileName), 
                generateWorksheetURL($(this).attr("ows_Control_x0020_Number1")), 
                subjectValue, 
                formatDate($(this).attr("ows_Suspense1")), 
                leadAgencyValue, 
                leadAoValue, 
                coordinationValue, 
                staffStatusValue, 
                staffAoValue, 
                forValue, 
                generateDocumentsURL($(this).attr("ows_Control_x0020_Number1")), 
                generateUploadURL($(this).attr("ows_Control_x0020_Number1"))];

                console.log("FileLeafRef = " + $(this).attr("ows_FileLeafRef"));


                listData.push(newRow);
            }
            else
            {
                console.log("SPServices failed");
            }
        });  
    }
}).then(LoadDataTableSupporting(listData));
Was it helpful?

Solution

You can use Promises and Deferreds to implement the asynchronous nature in the call. This way the table building activity will start only after fetching the list items. The Skeleton of the call is shared below. You can add the logic appropriately.

var listData = [];
function getListItems() {
var dfd = $.Deferred();
$().SPServices({
    operation: "GetListItems",
    listName: "ListOne",
    completefunc: function(data, status) {
        console.log("first is done");
        if (status == "success") {
            //do stuff . Populate listData Array to create table
            dfd.resolve("");
        } else {
            dfd.reject();
        }
    }
});
return dfd.promise();
}

**// The entry point. First calls getListItems method and then builds the table**
$.when(getListItems()).then(function() {
   console.log("Data retrieved. Build Table now");
});

Promises with SPServices Promises Implementation

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top