I am using SharePoint 2013 in the cloud. Due to restrictions in the site, I am using JSOM and jQuery to customize a site.

I have modified a Document Library edit form to create Tasks for each person based on a list (Memo). I need to set the previously created Task (Memo Tasks) as a prerequisite to the next created task. When I try to use the SPServices.SPGetLastItemId, I get the previous item twice, but on the third item, it stops updating. My guess is, not enough time has passed between the save and when I am calling the Get Last Item Id.

Is there a way that I can pause the while loop to give the server time to save the previous record, before going on to the next one?

Here is an out-line of my code:

Get ClientContext
Get List "Approvers"
Create Query
var lastId = 0;
Load Get Items Query
Execute Query Async
   While moveNext()
     // this function creates the task
     createTask(title, user, dueDate, lastId);
     // then get the lastId
     lastId = $().SPServices.SPGetLastItemId({ listName: "Memo Tasks" });

I even tried putting a global variable in the createTask function, but it seems that the while loop continues on before that function has completed what it is doing.


The setTimer function didn't work in the long run, because I couldn't get the PreItemSave action to continue after everything was done.

I tried to do a Deferred Object to respond back with a final TRUE value to the PreItemSave at the end of the updates, but I found that it would just continue on after the initial Task creation.

My final solution was to use a checkbox that I already had in the form to run the script to do the creations and updates and then use a .click() to save the form and have it continue. I made a made a little more wordy post on my blog.

Here is the final code snippet.

// Get Group Routing list based off of selected value

function startGroupRouting(groupRouting) {

    var clientContext = new SP.ClientContext.get_current();
    var approveList = clientContext.get_web().get_lists().getByTitle('Approvers');
    var approveQuery = new SP.CamlQuery();

    var ql = '<View>' +
        '<Query>' +
            '<Where><Eq>' +
              '<FieldRef Name="Routing_x0020_Group" />' +
              '<Value Type="Text">' + groupRouting + '</Value>' +
            '</Eq></Where>' +
            '<OrderBy>' +
                '<FieldRef Name="Step" Ascending="false"></FieldRef>' +
            '</OrderBy>' +
        '</Query>' +
    this.approveSelectList = approveList.getItems(approveQuery);
    clientContext.load(approveSelectList, 'Include(Approver,Approver_x0020_Type,Step)'); 

        Function.createDelegate(this, groupRouteSuccess),
        Function.createDelegate(this, onGetFail)

// After Success, Create Each Task

function groupRouteSuccess() {
    var memoDeliverDate = $('nobr:contains("Deliver By")').closest('tr').find('input[title^="Deliver By"]').val();
    var approveGrpEnumerator = approveSelectList.getEnumerator();
    // loop through list items
    var i = 0;
    var listCount = approveSelectList.get_count();
    var lastMemoCnt = listCount - 1;
    var lastMemo = false;
    while(i < listCount) {
        if(i == lastMemoCnt) {
            lastMemo = true;
        var thisGrpItem = approveGrpEnumerator.get_current();
        var approver = thisGrpItem.get_item('Approver');
        var approverType = new String(thisGrpItem.get_item('Approver_x0020_Type'));
        var step = new String(thisGrpItem.get_item('Step'));                        

        var clientContext = new SP.ClientContext.get_current();
        var oList = clientContext.get_web().get_lists().getByTitle('Memo Tasks');

        var today = new Date();
        var itemCreateInfo = new SP.ListItemCreationInformation();
        var oListItem = oList.addItem(itemCreateInfo);

        oListItem.set_item('Title', $.local.memoTitle + ' - ' + approverType);
        oListItem.set_item('Task_x0020_Group', $.local.memoTitle);
        oListItem.set_item('Step', step);
        oListItem.set_item('AssignedTo', approver);
        oListItem.set_item('Body', approverType);
        oListItem.set_item('DueDate', memoDeliverDate);
        oListItem.set_item('StartDate', today.format('M/dd/yyyy'));

        if(i == lastMemoCnt){
            clientContext.executeQueryAsync(createFinalTaskSuccess, onGetFail);
        } else {
            clientContext.executeQueryAsync(createTaskSuccess(step), onGetFail);

// Success for creating each task, except the last

function createTaskSuccess(step) {
    SP.UI.Notify.addNotification('New Task Created for Step ' + step);

// Success for creating each task, then start Task Update loop

function createFinalTaskSuccess() {
    SP.UI.Notify.addNotification('Final New Task Created');
    var clientContext = new SP.ClientContext.get_current();
    console.info("Starting Update Memo retrieve");
    var taskGrpList = clientContext.get_web().get_lists().getByTitle('Memo Tasks');
    var taskGrpQuery = new SP.CamlQuery();
    console.info("Query for Get Memos of taskGroup : " + $.local.memoTitle);
    var ql = '<View>' +
        '<Query>' +
            '<Where><Eq>' +
              '<FieldRef Name="Task_x0020_Group" />' +
              '<Value Type="Text">' + $.local.memoTitle + '</Value>' +
            '</Eq></Where>' +
            '<OrderBy>' +
                '<FieldRef Name="Step" Ascending="true"></FieldRef>' +
            '</OrderBy>' +
        '</Query>' +
    taskSelectGrpList = taskGrpList.getItems(taskGrpQuery);

            function() {
                var clientContext = new SP.ClientContext.get_current();
                var updTaskGrpList = clientContext.get_web().get_lists().getByTitle('Memo Tasks');
                console.info("Approval Group retrieve success");
                var taskGrpEnumerator = taskSelectGrpList.getEnumerator();
                var listCount = taskSelectGrpList.get_count();
                var lastMemoCnt = listCount - 1;

                console.info("Update memos retrieved: " + listCount + " lastMemo cnt = " + lastMemoCnt);
                while(taskGrpEnumerator.moveNext()) {
                    var oListItem = taskGrpEnumerator.get_current();
                for(var x = 1; x < listCount; x++) {
                    console.info("task(" + x
                        + ") ID = " + $.local.memoArray[x].get_item('ID')
                        + " predID = " +  $.local.memoArray[x-1].get_item('ID')
                        + " isLastUpdate = " + $.local.isLastUpdate);
                    var taskItem = updTaskGrpList.getItemById($.local.memoArray[x].get_item('ID'));
                    taskItem.set_item('Predecessors', $.local.memoArray[x-1].get_item('ID'));

                    if(x == lastMemoCnt) {
                        clientContext.executeQueryAsync(updateFinalTaskSuccess($.local.memoArray[x].get_item('ID')), onGetFail);
                    } else {
                        clientContext.executeQueryAsync(updateTaskSuccess($.local.memoArray[x].get_item('ID')), onGetFail);
        Function.createDelegate(this, onGetFail)

// Success for every Task update, except last one

function updateTaskSuccess(taskID) {
    SP.UI.Notify.addNotification('Task Predecessor Added to Task ' + taskID);

// Success for final Task Update

function updateFinalTaskSuccess() {
    SP.UI.Notify.addNotification('Task Predecessor Added to Final Task');
    console.info("Final Update Task Success");

// all fail

function onGetFail(sender, args) {
    var msgError = 'Request failed. ' + args.get_message() + '\n' + args.get_stackTrace();
    // add error message
    SP.UI.Notify.addNotification('Error : ' + args.get_message());
    console.error('Error occured: ' + msgError);

Here is code to make the thread wait for 3 seconds. Put this inside your while loop

var millisecondsToWait = 3000;
setTimeout(function() {
    // Whatever you want to do after 3 second sleep
}, millisecondsToWait);
  • I tried that, but it doesn't pause the while loop. – DeanLogic Jun 2 '15 at 20:47
  • Attempted to do a do while loop with the increment during the timeout, but that didn't slow it down either. – DeanLogic Jun 2 '15 at 20:59
  • I would try calling the SPGetLastItemId within setTimout. If that doesn't work, check out this thread stackoverflow.com/questions/22590280/… – Michael Colbs Jun 2 '15 at 21:05
  • 1
    @LoganSix setTimeout does not make the while loop pause, it just schedules the function within the setTimeout with a given delay. Since javascript is basically single threaded, the function in the setTimeout gets called after the current thread returns. – Dolgsthrasir Jun 3 '15 at 6:30
  • I would do nested calls to setTimeout and simulate the while loop with a recursive function. Did that before for something similar and it worked as intended. – Dolgsthrasir Jun 3 '15 at 9:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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