0

Newb here. I have tried multiple solutions found on SO and other places. This is the one I tried to follow to make sure my function didn't fire until all ajax calls have been made. For some reason, when my updateValues function fires the console log is not returning the data that was updated in my 'first' jQuery each function. However, if I click 'saveButton' again directly after the first time, the console log shows the correct data, as is updated by each function. I've followed all examples I've found but I'm stumped. Thanks in advance!

$("body").on("click",".saveButton",function(){
    var first = $(".item");
    var i = 0; 
    first.each(function(){
        var $this = $(this);
        var thisID = $this.find(".itemID").html();
        var itemProperties = {'Status': 'New'};
        updateListItem(_spPageContextInfo.webAbsoluteUrl,'TestList',thisID,itemProperties,printInfo,logError);
        i += 1;
        if(i == first.length) {
            updateValues();
        }
        function printInfo()
        {
            console.log('UPDATED!');
        }
        function logError(error){
            alert("An error occurred.");
            console.log(JSON.stringify(error));
        }
    });
    function printInfo(){
        console.log('UPDATED!');
    }
    function logError(error){
        alert("An error occurred.");
        console.log(JSON.stringify(error));
    }
});

function updateValues(){
    var url = _spPageContextInfo.siteServerRelativeUrl+
        "/_api/lists/getbytitle('TestList')/items?";
    $.ajax({
        url: url,
        method: 'GET',
        beforeSend: function (XMLHttpRequest){
            XMLHttpRequest.setRequestHeader('Accept', 'application/json; odata=verbose');
            },
        success: function( data ) {
            console.log(data);
            $(".itemTwo").each(function(){
                var $this =  $(this);
            });
        }   
    }); 
}

function updateListItem(webUrl,listTitle,listItemId,itemProperties,success,failure){
     var listItemUri =  webUrl + "/_api/web/lists/getbytitle('" + listTitle + "')/items(" + listItemId + ")";
     var itemPayload = {
       '__metadata': {'type': "SP.Data.IntakeTESTListItem"}
     };
     for(var prop in itemProperties){
           itemPayload[prop] = itemProperties[prop];
     }
     updateJson(listItemUri,itemPayload,success,failure);
}

function updateJson(endpointUri,payload, success, error){
    $.ajax({       
       url: endpointUri,   
       type: "POST",   
       data: JSON.stringify(payload),
       contentType: "application/json;odata=verbose",
       headers: { 
          "Accept": "application/json;odata=verbose",
          "X-RequestDigest" : $("#__REQUESTDIGEST").val(),
          "X-HTTP-Method": "MERGE",
           "If-Match": "*"
       },   
       success: success,
       error: error
    });
}
Omid Nikrah
  • 2,444
  • 3
  • 15
  • 30
loady toad
  • 53
  • 7
  • Ok. Lets go step by step. 1. You click `saveButton`. 2. `updateValues` function is called for each item. 3. After success `console.log` prints `data`. 4. The `data` is wrong. 5. You click `saveButton` again. 6... 7. The data is correct. Is this what you meant? – Papi Sep 16 '18 at 05:15
  • @Papi when i click 'saveButton' it loops through each of my $(".item") divs and updates their corresponding list item with my updateListItem function. After all those updates, I want the updateValues function to fire. My updateValues function fires but the first time I click it, it only logs the previous list values that were just changed by my updateListItem function. It's only if I then click 'saveButton' again that it registers the updated values. Hope this isn't too murky an explanation. – loady toad Sep 16 '18 at 05:24
  • I want the 'updateValues' function to change the list data, but I need to have the new values in order to do so. – loady toad Sep 16 '18 at 05:25
  • Hmmm, I see functions `updateValues` and `updateListItem` just logs some value but it's just a replacement for the implementation right? Also what may cause an issue: You have two async calls which are not ran synchronously. You probably wants to run `UpdateJson` after you'll receive response from `updateListItem`. Is that correct? – Papi Sep 16 '18 at 05:34
  • @Papi Yes, that is correct. UpdateJson should currently be running after updateListItem though with the way I have it set up, correct? – loady toad Sep 16 '18 at 05:45
  • Unfortunately not :) Please see my longer explanation below. – Papi Sep 16 '18 at 05:49

1 Answers1

1

tl;dr: You run two ajax calls, in this case the GET response is faster (fewer data to precede probably, or some other case) than the POST request so you'll get the outdated data at the first time.

Longer I hope more descriptive:

You have two ajax calls. The first one POSTs some stuff, the second one is GETs the stuff changed in POST request. Unfortunately they run at the same time. When js engine sees some ajax calls it's not waiting for the response to execute the next line but proceeds further. Callbacks in jquery's ajax calls are invoked in some future when the response comes back.

You probably want to run GET after you'll receive POST's success (or error, I don't know the use case). So you want to invoke updateValues functions after UpdateJson comes with response. With callbacks, it's messy - you'll have to pass updateValue to updateJson and invoke it on success. If you can, use promises - native fetch API or some lib like axios. It's much cleaner and readable.

TIP: You probably don't want to run ajax calls for each item. Instead run just one POST with all the data (if you have such endpoint) and one GET and then do for-each loop to update the frontend.

UPDATE I don't know jquery, but I've just seen in the linked question that jquery has when/then methods. Using them you can invoke next ajax request after some other was completed.

Papi
  • 741
  • 6
  • 8