- SPServices Stories #1 – How to Start a Workflow on Multiple Items in a List
- SPServices Stories #2 – Charting List Data with HighCharts
- SPServices Stories #3 – AddWebPart Method of the WebPartPages Web Service
- SPServices Stories #4 – Using SPServices to Process Files from a Non-Microsoft Source
- SPServices Stories #5 – Gritter and Sharepoint: Integrate Nifty Notifications in Your Intranet!
- SPServices Stories #6 – Custom Quizzing System
- SPServices Stories #7 – Example Uses of SPServices, JavaScript and SharePoint
- SPServices Stories #8 – CEWP, Nintex, jQuery, SPServices and the Client API
- SPServices Stories #9: Developing with Client-side Technologies: jQuery, REST, SPServices and jsRender
- SPServices Stories #10 – jqGrid Implementation Using SPServices in SharePoint
- SPServices Stories #11 – Using SPServices and jQuery to Perform a Redirect from a SharePoint List NewForm to EditForm
- SPServices Stories #12 – SharePoint and jQuery SPServices in Education: A Case Study
- SPServices Stories #13: Durandal SP3: Developing SharePoint SPAs Made Easy
Introduction
Given the fact that so many people are using SPServices these days, I wanted to start posting some of the great things that people are doing with it out there.
If you have a story about how you are using SPServices that you would like to tell, ping me using the contact form. Your story doesn’t even have to include code, though people love to see examples. I’m always interested in what impact using SPServices may have had on your development philosophy, time to market with solutions, hiring practices, really anything that you feel SPServices has enabled you to do.
We can remove any identifying details if you feel that need to do so, but I’d like these stories to show off what *you* have done, so it’s great if you can take credit. I reserve the right to do a little editing for clarity, but otherwise you can write your own story. I’m also happy to help.
The first guest post is from fellow SharePoint MVP, Alberto Diaz Martin, who lives in Spain. Thanks to Alberto for kicking this series off!
How to Start a Workflow on Multiple Items on a List
In SharePoint 2010 we have the option to select multiple items on a list. When you select several items, the ribbon allows you to Delete Items and Send Alerts, but where is the Workflow command?
To start a workflow on a list item, you have to go through the Start workflow page and if the workflow has an initialization form, you also have to enter the parameters. Because of this, SharePoint doesn’t allow users to start a workflow on multiple items simultaneously. But why not do so when we have a parameter-less workflow?
I think this is a missing feature on SharePoint 2010 because we can certainly do it using the SharePoint API or Web Services without any problems. What can we do to provide this capability to our users?
First, we need to create a Ribbon command using a Custom Action and in this action we will have two options to try to start the workflow. The first one uses an application page by passing the selected items as parameters and uses the server API to start the process. The second, and more flexible and elegant option is using JavaScript and the SharePoint Web Services to start each workflow per item.

SharePoint Web Services are a horrible way to talk with SharePoint [ed: I disagree, but everyone is entitled to their opinion!] because the Web Services use XML to get and put parameters and options, and it’s not easy working with XML in JavaScript.
SPServices to the Rescue!!
As you know, SPServices is a jQuery library which encapsulates SharePoint Web Services with jQuery to make it easy to call them. SPServices has a Workflow namespace with some powerful operations and we can use StartWorkflow to start an item workflow, even if it has parameters.
It is so easy to use, you only need the Item URL, the workflow template Id and, if required, the workflow parameters.
$().SPServices({
operation: "StartWorkflow",
item: currentItemURL,
templateId: workflowGUID,
workflowParameters: workflowParams,
async: true,
completefunc: function () {
SP.UI.Notify.addNotification("Workflow process started on selected item.", false);
}
});
To get the workflow template Id, we have another function called GetTemplatesForItem that returns all the associated workflows for an item. All we have to do is get all the templates and find our workflow by name.
$().SPServices({
operation: "GetTemplatesForItem",
item: itemURL,
async: true,
completefunc: function (xData, Status) {
var currentItemURL = this.item;
$(xData.responseXML).find("WorkflowTemplates > WorkflowTemplate").each(function (i, e) {
if ($(this).attr("Name") == "Invoice Approve") {
var guid = $(this).find("WorkflowTemplateIdSet").attr("TemplateId");
if (guid != null) {
workflowGUID = "{" + guid + "}";
//in this point, we have our workflow Id and we have to call the starting method
}
}
}
}
})
Now, we have to traverse the selected items in the custom action method, and for each item call the SPServices StartWorkflow method. Something like this:
function StarSignWorkflow(listId) {
RemoveAllStatus(true);
waitDialog = SP.UI.ModalDialog.showWaitScreenWithNoClose('Starting approval workflow process on selected item','Please,wait until we finished this long operation.',76,400);
//Get the selected items
clientContext = new SP.ClientContext.get_current();
var web = clientContext.get_web();
var list = web.get_lists().getById(listId);
var items = SP.ListOperation.Selection.getSelectedItems(ctx);
totaSelItems = items.length;
//Because only have items Id,we need to use Client Object Model to get EncodeAbsUrl.
var query = new SP.CamlQuery();
var queryString = '<View><Query><Where><In><FieldRef Name="ID"/><Values>';
for (index in items) {
var valueString = '<Value Type="Integer">' + items[index].id + '</Value>';
queryString = queryString + valueString;
}
query.set_viewXml(queryString + '</Values></In></Where></Query></View>');
this.collListItems = list.getItems(query);
clientContext.load(collListItems,'Include(EncodedAbsUrl)');
//In the success callback,we’ll have all the selected items with the absolute url.
clientContext.executeQueryAsync(Function.createDelegate(this,this.onInitProcessSuccess),Function.createDelegate(this,this.onInitProcessFail));
}
function onInitProcessSuccess() {
var listItemEnumerator = this.collListItems.getEnumerator();
//If our workflow has default init param,we can provide it in this way to run workflow with default values.
var workflowParams = "<Data><Approvers></Approvers><NotificationMessage></NotificationMessage>" +
"<DurationforSerialTasks></DurationforSerialTasks><DurationUnits></DurationUnits>" +
"<CC></CC><CancelonRejection></CancelonRejection><CancelonChange></CancelonChange>" +
"<EnableContentApproval></EnableContentApproval></Data>";
try {
var counter = 1;
var total = totaSelItems;
//Traverse all the selected items
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
var itemURL = oListItem.get_item('EncodedAbsUrl');
var workflowGUID = null;
//Before start the workflow,we used GetTemplatesForItem to get Workflow Template Id.
$().SPServices({
operation: "GetTemplatesForItem",
item: itemURL,
async: true,
completefunc: function (xData,Status) {
var currentItemURL = this.item;
$(xData.responseXML).find("WorkflowTemplates > WorkflowTemplate").each(function (i,e) {
if ($(this).attr("Name") == "Invoice Approve") {
var guid = $(this).find("WorkflowTemplateIdSet").attr("TemplateId");
if (guid != null) {
workflowGUID = "{" + guid + "}";
$().SPServices({
operation: "StartWorkflow",
item: currentItemURL,
templateId: workflowGUID,
workflowParameters: workflowParams,
async: true,
completefunc: function () {
if (total == counter) {
if (waitDialog != null) {
waitDialog.close();
}
SP.UI.Notify.addNotification("Started workflow approved process for selected invoice.",false);
window.location.reload();
}
counter++;
}
});
}
}
});
}
});
}
}catch (e) {
if (waitDialog != null) {
waitDialog.close();
}
AddStatus("There is an exception. Error: " + e.message,"red");
}
}
As you can see, you have an easy way to provide an easy way to start a process on multiple items at the same time. Thanks to SPServices, working with SharePoint client side is more flexible and easy.
Alberto Diaz Martin
MVP SharePoint
adiazcan@hotmail.com
@adiazcan
http://geeks.ms/blogs/adiazmartin




6 comments
Skip to comment form ↓
docsridhar
January 25, 2013 at 10:18 pm (UTC -4) Link to this comment
Please add steps to do this using SP designer.
Marc
January 28, 2013 at 9:21 am (UTC -4) Link to this comment
docsridhar:
There are many posts here on my blog as well as elsewhere that take you through the steps to implement script-based solutions. If you have specific questions about this specific method, please post them back, but otherwise you’ll need to do more homework.
M.
Chris
February 9, 2013 at 7:52 am (UTC -4) Link to this comment
Hi Marc,
Thank you so much for your great work!
I have problems fully understanding your script. To be specific in lines 14, 16 and 19 you are concatenating empty strings. I always thought there should be CAML expressions?
In the current script the id numbers are connected without any space in between. Or have I missed sth.?
Could you give me some Information on that please?
Best regards from Austria!
Marc
February 9, 2013 at 11:09 am (UTC -4) Link to this comment
Chris:
Good catch. Sometimes WordPress eats some of the code in my posts and I miss it.
Thanks,
M.
JLSF
February 10, 2013 at 1:30 am (UTC -4) Link to this comment
Hello
I´ve been checking your SPServices Package,
What i see, or well did not see, is any reference to sharepoint 2013 or the apps model.
I think this is well suitable when developing sandboxes solutions or farm solutions, and not suites for apps right?
Thanks
Marc
February 10, 2013 at 1:33 am (UTC -4) Link to this comment
JLSF:
I haven’t done extensive testing with SharePoint 2013, but the SOAP Web Services are very much alive and kicking, though they have been deprecated. Some would say that the right way to go for apps is the SharePoint CSOM, but the SOAP Web Services still provide some capabilities that aren’t there yet.
M.