I need to use JSOM to copy a set of items (found from a CAML query) from one SharePoint list to another.
I'm pretty experienced doing this type of thing on the server side, but relatively new with it on the client side, with the async model. Based on my research, I need to use promises
to do this, since I need to know when the copy is complete and whether or not any errors occurred.
I also need to copy the items one at a time, rather than batching them, because there can be a large number of items to copy, with many fields, and I run into message size errors from SharePoint if I try to do them all as one batch.
Below is a snippet of my code (with some irrelevant things removed). This appears to be working - except for one thing. As it does the copy of the items, I update a div
on the page with the item number (just a counter) being copied as a progress indicator. Two things I notice:
The div is not updated with the counter sequentially. With the promise, I guess I expected to see
1, 2, 3, 4...
but the numbers jump around, not sequential. Not a big deal, just not what I expected.This is more of an issue. In my code, I have a function
updateSuccessFinal
that I call after the.done()
, which callsalert()
to notify the user the copy is complete. However, while that alert is displayed, I can see thediv
still being updated with item numbers, meaning it is still doing the copying. I need this alert to only display when all of the items have been written. If the user dismisses the alert, there could be items that were not copied because they were still queued up.
Am I using the promise
incorrectly in my code? How can I insure that the function updateSuccessFinal
is not called until all items have been written?
I am using d = $.Deferred() inside my addItem
function. I have also tried moving that outside the loop and passing d to addItem
and that did not seem to make any difference.
function snapshotItems(sourceListName, queryText, targetListName)
{
// Snapshot all of the items picked up in the criteria of view view into the snapshot list
var context = new SP.ClientContext.get_current();
var srcList = context.get_web().get_lists().getByTitle(sourceListName);
// Create query
var query = new SP.CamlQuery();
query.set_viewXml(queryText);
// Items matching the query
var items = srcList.getItems(query);
context.load(items);
// Insert the rows in the Snapshot table
context.executeQueryAsync(
function()
{
var listEnumerator = items.getEnumerator();
var i = 0;
while (listEnumerator.moveNext())
{
var curListItem = listEnumerator.get_current();
addItem(curListItem, i).done(
function() {
}
);
i++;
}
snapshotSuccessFinal();
},
function(sender, args)
{
alert('Get snapshot query failed: ' + args.get_message());
}
);
function addItem(curListItem, i)
{
// Need to use promises because batching all the adds results in a "message too large" error from SharePoint
// So uses promises to execute one add at a time
var d = $.Deferred();
var context = new SP.ClientContext.get_current();
var targetList = context.get_web().get_lists().getByTitle(targetListName);
var itemCreateInfo = new SP.ListItemCreationInformation();
var listItem = targetList.addItem(itemCreateInfo);
// Copy the custom fields
listItem.set_item("Title", curListItem.get_item("Title"));
// Write it
listItem.update();
context.load(listItem);
var passedData = { dfd: d, idx: i };
context.executeQueryAsync(Function.createDelegate(passedData,onUpdateOneSuccess), Function.createDelegate(passedData,onUpdateOneFailed));
return d.promise();
}
function onUpdateOneSuccess()
{
$("workingDiv").text("Snapshot item #" + this.idx.toString());
this.dfd.resolve();
}
function onUpdateOneFailed()
{
alert("Add item failed: " + args.get_message())
}
}
function snapshotSuccessFinal()
{
$("workingDiv").text("Snapshot populated.");
alert("Snapshot created successfully.");
}