0

We are trying to copy contents from one column to the other , However we get request digest error after 6K Items.

Below is the code

$(document).ready(function () {
 
 $("#btnSubmit").click(function () {   
 
  GetItemId();

 });
 
 }); 
 
 
 function UpdateListItemUsingItemId(Id, Ptype) {
            //var deferred = $.Deferred();
            
                //console.log(base64Img);
                var _listItem = {
                    "__metadata": { 'type': 'SP.Data.PCFHeaderListItem' },

                    "PType": Ptype
                };


                $.ajax({
                    url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/Lists/GetByTitle('DBSDistributorList')/Items(" + Id + ")",
                    method: 'POST',
                    contentType: "application/json;odata=verbose",
                    async: false,
                    data: JSON.stringify(_listItem),
                    headers: {
                        "accept": "application/json;odata=verbose",
                        "X-RequestDigest": $("#__REQUESTDIGEST").val(),
                        "content-Type": "application/json;odata=verbose",
                        "X-Http-Method": "MERGE",
                        "If-Match": "*"
                    },
                    success: onSuccess,
                    error: onError
                    /*success: function (data) {
                        deferred.resolve(data);
                    },
                    error: function (err) {
                        deferred.reject(err);
                    }*/   
                });
                //return deferred.promise();        
        
       
        function onSuccess(data) {
           console.log('List Item Updated');
        }

        function onError(error) {
           console.log(JSON.stringify(error));
        }
      
   };

       
    function GetAllItems(requestUrl) {
    var deferred = $.Deferred();
    $.ajax({
        url: requestUrl,
        method: "GET",
        headers: {
            "accept": "application/json;odata=verbose",
        }
    }).done(function (thisResult) {
        if (thisResult.d.__next) {
            // if the __next property is present,
            // that measn that there's more to get,
            // so don't start resolving things yet,
            // just make the next request
            var nextRequest = GetAllItems(thisResult.d.__next);
            
            // since GetAllItems returns a promise,
            // we have to wait for that promise to resolve
            // before resolving the promise we made 
            // at the beginning of this function
            nextRequest.done(function(nextResult) {
                // nextResult should be a plain array of items,
                // so we need to combine that with the array
                // of items we got in this call in thisResult.d.results
                var combinedResults = thisResult.d.results.concat(nextResult);
                
                // then resolve the combined results back up to the next level
                deferred.resolve(combinedResults);

            }).fail(function(error) {
                deferred.reject(error);
            });
        } else {
            // __next doesn't exist, so
            // there's nothing more to get, so
            // start resolving the nested promises
            deferred.resolve(thisResult.d.results);
        }
    }).fail(function (result) {
        deferred.reject(result);
    });
    return deferred.promise();
};
        
        
       
function GetItemId()
{
  var initialUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/Web/Lists/GetByTitle('PCFHeader')/Items?$select=ID,Project_x0020_Type";

// start the process
var getAllItemsRequest = GetAllItems(initialUrl);

// wait for it all to complete
getAllItemsRequest.done(function (allItems) {
    // allItems should now be
    // an array of all 700+ items
    
    // make sure your request digest value is good
    // using the built-in SP provided function for doing just that
    UpdateFormDigest(_spPageContextInfo.webServerRelativeUrl, _spFormDigestRefreshInterval);
    
    $.each(allItems, function (index, row) {
        UpdateListItemUsingItemId(row["ID"], row["Project_x0020_Type"]);
    });
}).fail(function (error) {
    console.warn("Error getting all items");
    console.warn(JSON.stringify(error));
});
}

Error

"The security validation for this page is invalid and might be corrupted. Please use your web browser's Back button to try your operation again."

Please advice

Thanks in advance.

1 Answer 1

1

In your original question, you were dealing with around 700 items, so updating the form digest once before looping through all the items made sense, because it was very likely that the form digest would not expire before all the POST update calls were made. But now you are implying that you are looping through 16,000 items, which is a lot more than the original 700. So it makes sense that the updates might take long enough that the form digest does expire before all your POSTs are done.

So, just move the UpdateFormDigest() call from here:

UpdateFormDigest(_spPageContextInfo.webServerRelativeUrl, _spFormDigestRefreshInterval);

$.each(allItems, function (index, row) {
    UpdateListItemUsingItemId(row["ID"], row["Project_x0020_Type"]);
});

to inside the UpdateListItemUsingItemId function, just before you make each ajax call, to ensure that the form digest is always valid:

function UpdateListItemUsingItemId(Id, Ptype) {
    var _listItem = {
        "__metadata": { 'type': 'SP.Data.PCFHeaderListItem' },
        "PType": Ptype
    };

    UpdateFormDigest(_spPageContextInfo.webServerRelativeUrl, _spFormDigestRefreshInterval);
    $.ajax({
            // options
        },
        success: onSuccess,
        error: onError
    });

    // etc
}

Another way to approach this would be, instead of calling UpdateFormDigest immediately before every update POST attempt, start off an independent, separate process that is responsible for occasionally refreshing the form digest.

This technique is described at the end of this blog post, but essentially what you would do is go back to something closer to what you had originally, so remove the UpdateFormDigest call from the UpdateListItemUsingItemId function, and then just before you loop through all your items to update them, use setInterval() to do something like this:

// call it once to make sure the form digest is refreshed
// before you make your first update attempts
UpdateFormDigest(_spPageContextInfo.webServerRelativeUrl, _spFormDigestRefreshInterval);

// use setInterval to set up a repeating call to UpdateFormDigest
// that will automatically run every 5 minutes (form digest expires
// after 30 minutes, so that should easily be often enough)
setInterval(function() {
    UpdateFormDigest(_spPageContextInfo.webServerRelativeUrl, _spFormDigestRefreshInterval);
}, 5 * 60 * 1000);

// now you can loop through as many items as you want, because
// the setInterval loop will continually refresh the form digest
$.each(allItems, function (index, row) {
    UpdateListItemUsingItemId(row["ID"], row["Project_x0020_Type"]);
});
5
  • Thanks Dylan , Trying this now :)
    – Vivek
    Mar 8, 2021 at 15:54
  • Dylan , it is giving 429 too many request (throttling) error.. any suggestions on how to work around this at the code level?
    – Vivek
    Mar 8, 2021 at 16:25
  • Again, I would suggest posting this as a different question, since it is a different problem. Mar 8, 2021 at 17:57
  • @Vivek updated my answer with another idea for how to automatically keep the form digest fresh over a long period of time. Mar 8, 2021 at 18:19
  • Thanks a lot Dylan.. managed to get it to work without 429 errors :)
    – Vivek
    Mar 9, 2021 at 9:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.