0

I've been reading a lot of these posts to try and figure things out but still have some questions.

The sequence of events is Edit screen displays, user enters data, and submits(I have omitted that code on purpose as it works). On the submit new list item is created in list 2 with some info from the from and from list 1. Then list 1 is updated.

My code has three ExecuteQueryAsync blocks. Get info from list1, Create new item in list 2(from list 1 and user input), and update item in List 1 (from user input). There may be (and probably is) an easier way but I'm new so there you go. Using promises to process these.

Thanks so much in advance. This is driving me crazy to get this far and not have it work.

It is the last item (update) that is not firing which you can see at the second .then. At the moment the UpdateListItem has no code as I was testing to see if it would fire. Once I understand and get that part to fire I plan to put the async code to process.

function GetSomeData(ItemID, siteURL, srcListName, IntNames, srcFieldVals, tInternalNames) {
    GetListItem(ItemID, siteURL, srcListName, IntNames, srcFieldVals, tInternalNames)

        .done(function (mylist) {

            srcFieldVals['ProjName'] = mylist.get_item(IntNames['ProjName']);

            $("#lemydateold").text(srcFieldVals['LE'].toLocaleDateString('en-us'));

        })

        .then(function (mylist) {   // Updates target list (shedule test)

            console.log(' then completed');
            NewSchedListItem(mylist, IntNames, tInternalNames);

        })
        .then(function (mylist) {  //THIS BLOCK DOES NOT FIRE
            UpdateListItem(mylist);
        }))
};


function GetListItem(myID, siteURL, srcListName) {

    var ctx = new SP.ClientContext(siteURL);
    console.log('Get List Item Handler');
    this.list = ctx.get_web().get_lists().getByTitle(srcListName);
    this.listitem = list.getItemById(myID);
    ctx.load(listitem);

    ctx.executeQueryAsync(
        this.OnSuccessGet.bind(this),
        this.OnFailGet.bind(this),
    );
    return deferred.promise();
};

function OnSuccessGet(sender, args) {

    deferred.resolve(listitem);
}

function OnFailGet(sender, args) {

    deferred.reject(sender, args);
}

function NewSchedListItem(srclistitem, srcIntNames, tIntNames) {

    var ctxNew = new SP.ClientContext("https://someurl.com");

    var tlist = ctxNew.get_web().get_lists().getByTitle('Schedule-TEST');
    var itemCreateInfo = new SP.ListItemCreationInformation();
    this.tListItem = tlist.addItem(itemCreateInfo);

    tListItem.set_item(tIntNames['ProjName']), srclistitem.get_item(srcIntNames['ProjName']);

    tListItem.Update();
    ctxNew.load(tlistitem);

    ctxNew.executeQueryAsync(
        this.OnSuccessNewSched.bind(this),
        this.OnFailNewSched.bind(this),
    );
    return deferred.promise();
};

function OnSuccessNewSched(sender, args) {

    deferred.resolve(listitem);
}

function OnFailNewSched(sender, args) {

    deferred.reject(sender, args);
} 


function UpdateListItem(mylist){
    console.log('at update list function');
}
  
function GetItemID(mylink){
    var myid=mylink.substring(mylink.indexOf("?")+1,mylink.indexOf("&"));
    var ItemID=myid.substring(myid.indexOf("=")+1);
    return ItemID;
}

1 Answer 1

0

Off the top of my head what I would say is that although your NewSchedListItem function returns a Deferred.promise(), what is happening is that it is returning that object into the scope of the anonymous function you use in your then handler, and not out to the then handler itself, so it is not handled correctly in the chain.

What you need to do is return the Promise that is returned from the NewSchedListItem function out of the anonymous function so it can then be handled by the next then handler:

function GetSomeData(ItemID, siteURL, srcListName, IntNames, srcFieldVals, tInternalNames) {
    GetListItem(ItemID, siteURL, srcListName, IntNames, srcFieldVals, tInternalNames)
        .done(function (mylist) {
            srcFieldVals['ProjName'] = mylist.get_item(IntNames['ProjName']);
            $("#lemydateold").text(srcFieldVals['LE'].toLocaleDateString('en-us'));
        })
        .then(function (mylist) {   // <- this is an anonymous function, which creates its own scope
            console.log(' then completed');
            
            // you need to return the promise that is returned from
            // the NewSchedListItem function back _out_ of the
            // anonymous function so it can be handled by the next "then"

            return NewSchedListItem(mylist, IntNames, tInternalNames);
        })
        // this "then" handler receives nothing to handle if you don't 
        // return the promise out of the anonymous function above
        .then(function (mylist) {  
            UpdateListItem(mylist);

        })) // <- my code editor says that you have an extra close-parentheses here that you don't need
};

So to address your comment

so, if I am understanding you correctly each of my functions (GetItem, CreateItem, and Update item) each need their own respective promises?

Yes, and in fact on further review of your code, I don't see where you are creating the deferred object you are using to return Promises out of those functions. You need to create individual deferred objects within the scopes of those functions so that those Promises refer to only the async processes they are helping to control. (Also I see that in your then handler functions, you are naming the argument passed into the function as mylist which is a bit misleading, because what actually gets passed in is the value resolved by the promise, which according to those lines of code is actually a list item, not a list.)

I've removed some of your code where you actually do stuff with SharePoint, and added a lot of comments, to hopefully highlight how things are working with the promises, async calls, and handler chaining:

function GetSomeData(ItemID, siteURL, srcListName, IntNames, srcFieldVals, tInternalNames) {
    GetListItem(ItemID, siteURL, srcListName, IntNames, srcFieldVals, tInternalNames)
        // this "done" will be triggered by the successful resolution
        // of the "getItemDfd.promise()" returned from GetListItem
        .done(function (listitem) {
            srcFieldVals['ProjName'] = listitem.get_item(IntNames['ProjName']);
            $("#lemydateold").text(srcFieldVals['LE'].toLocaleDateString('en-us'));

            // at this point the "done" handler is going to automatically return
            // out to the chain the _same_ resolved promise from GetListItem,
            // so it will automatically trigger the next "then" handler
        })
        .then(function (listitem) { // <- this is still an anonymous function with its own scope

            var promiseFromNewSchedItem = NewSchedListItem(listitem, IntNames, tInternalNames);

            // at this point the promise returned out of
            // NewSchedListItem is trapped inside the scope of this anonymous
            // function, so to trigger the next "then" handler, you need to
            // return it out to the chain:

            return promiseFromNewSchedItem;

            // that can be shortened to one line of code, as i posted in my original answer:
            // return NewSchedListItem(listitem, IntNames, tInternalNames);
        })
        // this "then" handler receives nothing to handle if you don't 
        // return the promise out of the anonymous function above
        .then(function (listitem) {  
            UpdateListItem(listitem);

            // as mentioned in the comment inside the UpdateListItem
            // function, if you need to continue chaining, you will need
            // to have UpdateListItem return its own promise, which
            // you will then have to return out of this anonymous function
            // and on to another "then" handler
        });
};

function GetListItem(myID, siteURL, srcListName) {
    // create a new deferred object for this scope
    var getItemDfd = $.Deferred();

    // do what you need to make the async call

    ctx.executeQueryAsync(
        // success
        function(sender, args) {
            // use the deferred object that represents this async action
            getItemDfd.resolve(listitem);
        },
        // fail
        function(sender, args) {
            getItemDfd.reject(sender, args);
        }
    );
    // return the promise that represents this particular async action
    return getItemDfd.promise();
};

function NewSchedListItem(srclistitem, srcIntNames, tIntNames) {
    // create a new deferred object for this scope
    var newSchedItemDfd = $.Deferred();

    // do what you need to make the async call

    ctxNew.executeQueryAsync(
        // success
        function(sender, args) {
            // use the deferred object that represents this async action

            // and, it looks like in the original chain, the item that
            // you are tying to pass into the next "then" handler is the same list
            // item that was returned from teh original GetListItem call, which
            // was passed into this function as "srclistitem", so to pass it on
            // we need to resolve the promise with that object
            newSchedItemDfd.resolve(srclistitem);
        },
        // fail
        function(sender, args) {
            newSchedItemDfd.reject(sender, args);
        }
    );
    // return the promise that represents this particular async action
    return newSchedItemDfd.promise();
};


function UpdateListItem(srclistitem){
    console.log('at update list function');

    // if you need to do more stuff after
    // doing an async action in this function,
    // then you will need to create a new deferred object for this scope,
    // and return its promise out of here, so that you 
    // can then return it out of the anonymous function that called
    // this function and back out into another chained "then" handler
}

Also, you might want to read up on the documentation for jQuery deferred.done() and jQuery deferred.then().

5
  • so, if I am understanding you correctly each of my functions (GetItem, CreateItem, and Update item) each need their own respective promises?
    – Pablo
    Sep 23, 2020 at 17:04
  • Basically, yes. And after further review of your code, I see some other things that may need to be addressed. But before I add that to my answer, a question for you: I am assuming that since you are using deferred.promise() that implies you are actually using jQuery? Is that correct? If not - where does the deferred come from? Sep 23, 2020 at 17:51
  • I am using Jquery and this work is targeted at two sharepoint lists.
    – Pablo
    Sep 23, 2020 at 17:53
  • @Pablo updated my answer Sep 23, 2020 at 18:52
  • I think I figured it out. Your question made me think about this more and I rewrote the above and now it looks like it's running in the sequence I need it to run in. Thanks so much for taking the time to look into this though...you helped to make something click on my end (finally)! LOL
    – Pablo
    Sep 23, 2020 at 20:31

Your Answer

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

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