SPServices Stories #1 – How to Start a Workflow on Multiple Items in a List
- 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
- SPServices Stories #14: Create a Slide Show in SharePoint 2010 using an Announcements List and SPServices
- SPServices Stories #15: Custom Client-side Calendar Query for Office 365 SharePoint Site Using SPServices jQuery Library
- SPServices Stories #17: Multiple Form Fields Autocomplete for SharePoint 2010/2013 using JavaScript
- SPServices Stories #18 – Retrieve Managed Metadata Using JavaScript and SPServices
- SPServices Stories #19 – Folders in SharePoint are as necessary as evil. Make the best of it using jQuery and SPServices.
- SPServices Stories #20 – Modify User Profile Properties on SharePoint Online 2013 using SPServices
- SPServices Stories #22 : SPServices SharePoint Attachments in Internet Explorer 9
- SPServices Stories #21 – Redirect If User Clicked a Button Previously
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!
[important]You can also read this post in Spanish on Alberto’s blog SharePoint 2010. Iniciar un flujo de trabajo en múltiples elementos de una lista[/important]
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
[email protected]
@adiazcan
http://geeks.ms/blogs/adiazmartin
Why is the code cut off on the right side? Can you please post the code?
Thanks.
Toby:
You should be able to scroll left/right at the bottom of each code window. Also, if you hover over the code window, you’ll see a little toolbar in the upper right where you can copy the code as text.
M.
Hi thanks for this nice article,can you please provide the steps you have worked …it will be easy for us to learn
This is awesome. Very fast and worked like a charm. Thanks for sharing, saved me a lot of trouble.
Is there an alternative way to get the template ID for the WorkFlow? I have SharePoint 2013 cloud hosted and I can’t find a place that will show the URL in order to get the template ID.
Great article, but unable to get this to work on a document library. As Marc suggested, I did my homework, lots of it, but still no go. The basics are missing from the article, which for an expert like Marc may be okay, but for us mere mortals, some basic information would be helpful. For example, how to trigger this think. How to configure the custom action button would be helpful. What values needs to be added to the script so that it works in different environments. It would be appreciated. Thanks
Hi Marc, I am getting this error :jquery-1.7.2.min.js:4 POST http://vswm:5805/sites/ShoppingCart/_vti_bin/Workflow.asmx 500 (Internal Server Error) on checking the ULS logs I get this error:Workflow Soap: StartWorkflow failed Item: http://vswm:5805/sites/ShoppingCart/RecordsLibrary/Web%20Developer%20Tools%20EULA.rtf TemplateId: 6adfe111-f615-434d-9c7c-4aa653b0ee08 Data at the root level is invalid. Line 1, position 1. Error: Data at the root level is invalid. Line 1, position 1. Please help me..
@Disha:
I’d suggest a more current version of jQuery, but that’s not the issue. The error is telling you the payload you’re sending isn’t valid XML.
M.
Marc: I am sorry I didn’t get you… I just implemented the code you have posted in both SP2010 and SP2013 … I get this error on both the environments.. Is the SOAP XML that you are talking about? I am new to SOAP and WebService so don’t have much idea about it.. Could you please help me out?
Hi Marc, I was able to solve this issue. My workflow did not have parameters so I was passing null value. Instead of that I added as the parameter and it worked. Thanks a lot for such a helpful post.
That’d do it! Glad you figured it out…
M.
Very frustrating:
I usually work with SPServices and they are easy to implement in content editor. I tried many different approaches to get this working. Just beats me.
– I tried adding an html button on a content editor and call the Javascript function sitting within the head tag of the script on onclick event. I keep getting XSS errors
– So i created 2 different content editors separating html and script. Still doesn’t work.
– I finally added the link to the script in the web part properties and it gives the same XSS error
– I tried adding the custom view ribbon button, but i have never done a javascript run through it. In one of the question above, one of the person mentioned that they used javascript:openChildWindow(‘’) method. I added this pointing to the JScript in my Site Assets page. But nothing happens when i click the ribbon button.
Any help would be appreciated
Hello,
I tried following what you did by calling the javascript:openChildWindow/OpenChildWindow() and I get an error saying its not defined. How do you call the function by pointing to an html page?
Ok, I think I figured it out. There is a good resource on this:
http://www.javascriptkata.com/2007/04/19/how-to-do-a-bookmarklet-with-javascript/
Thanks for the post, it was great help.