1

I was presented with a task to run a workflow via jQuery. I know that SPServices has this capability, but I have never tried it before being assigned this task. So I set out and found some good references. After creating the link in XSL and the jQuery script, the workflow is not starting and SPServices is returning an error since the responseXML is undefined.

XSL code which passes parameters and calls js function

<a href="#">
    <xsl:attribute name="onclick">
    <xsl:text>javascript:StartWorkflow('</xsl:text>
    <xsl:value-of select="@EncodedAbsUrl" disable-output-escaping="yes"/>
    <xsl:text>','</xsl:text>
    <xsl:value-of select="@ID" disable-output-escaping="yes"/>
    <xsl:text>','myListName','emailTest');</xsl:text>
    </xsl:attribute>
Email Me</a>

The parameters passed to StartWorkflow function are the Encoded URL of the list item, the ID of the item, the list in which the item resides and the name of the workflow I want to run, respectively. I can verify that the workflow is grabbing the parameters as string objects.

Javascript functions that should process the workflow

function StartWorkflow(ItemURL, ItemID, ListName, DesiredWorkflow)  {
    var id = "";
    $().SPServices({
        operation: "GetList",  
        listName: "myListName",  
        async: false,  
        completefunc: function (xData, Status) {  
            id = $(xData.responseXML).find("List").attr("ID").toString();  
        }  
    });
    //Get list Id from current page 
    if (id) { 
        this.guid = new SP.Guid(id); 
        var context = SP.ClientContext.get_current(); 
        var lists = context.get_web().get_lists(); 
        var list = lists.getById(this.guid); 
        //Set workflows variable to load and be accessible in callbacks 
        this.workflows = list.get_workflowAssociations(); 
        context.load(this.workflows); 
        context.executeQueryAsync(Function.createDelegate(this, onQuerySucceeded), Function.createDelegate(this, onQueryFailed)); 
    } 
    function onQuerySucceeded(sender, args) { 
        var enumerator = this.workflows.getEnumerator(); 
        while (enumerator.moveNext()) { 
            var workflow = enumerator.get_current();
            if (workflow.get_enabled() && workflow.get_allowManual()) { 
                var workflowName = workflow.get_name(); 
                if (workflowName == DesiredWorkflow){
                    var workflowGuid = '{' + workflow.get_id().toString() + '}';
                    //alert(workflowName + "  .....  " + workflowGuid);
                    RunWorkflow(ItemURL, ItemID, workflowGuid);
                }
            }
        } 
    } 
    function onQueryFailed(sender, args) { 
        alert('Unable to retrieve workflows: ' + args.get_message()); 
    } 
}
function RunWorkflow(ItemURL, ItemID, workflowGuid)  {
    var loadingImage = 'Loader' + ItemID;
    var workflowDiv = 'WorkflowDiv' + ItemID;
    var workflowParams = "<root />";
    //Show our loading image
    document.getElementById(loadingImage).style.visibility = 'visible';
    $().SPServices({
        operation: "StartWorkflow",
        async:true,
        item: ItemURL,
        templateId: workflowGuid, 
        workflowParameters: workflowParams,
        completefunc: function (xData, Status) { 
            if(Status != "error"){
                document.getElementById(workflowDiv).innerHTML = 'Item emailed';
            }
            else{
                document.getElementById(workflowDiv).innerHTML = '<div style=\"color:#FF0000\">Error</div>';
                if (xData.responseXML != undefined)
                    window.alert(xData.responseXML.text);
                else
                    window.alert("Error. call assistance, probably the workflow was changed and has another GUID.");            }

        }
    });
}

I ran Fiddler to see if I could find where issues are starting. Fiddler is returning a 404 error when the StartWorkflow SPServices call runs. The SPServices GetList call works fine as long as I do not pass a parameter for listName (I have to type out list name, which is annoying since it adds a few more steps in making the script reusable.

The script is running through the end of the completefunc in the StartWorkflow SPServices call but then has a "Status" = "Error" and the responseXML is undefined. This results in a workflow not running via jQuery. Any advice on where the issue may be starting would be greatly apprecited.

1

In scenarios where I needed to have the ability to start a workflow via a hyperlink, I daisy-chained 2 functions, GetTemplatesForItem and StartWorkflow. GetTemplatesForItem gives you the proper GUID of the workflow you wish to start and then you pass that data along into the StartWorkflow function. In the second link, note the proper format the URL needs to be in.

So to trigger it on my hyperlink click, I'd just pass the ID of the item into my function, build the proper URL, find the workflow GUID, then pass the GUID and item URL into the start workflow function.

You can do this all in jQuery too, no need to use the client object model.

Edit: Here is a post from the discussions on how I did it.

<script type="text/javascript">
function StartWorkflow(ItemURL, ItemID) {
var workflowGUID = null;
$().SPServices({
  operation: "GetTemplatesForItem",
  item: ItemURL,
  async: false,
  completefunc: function (xData, Status) {
    $(xData.responseXML).find("WorkflowTemplates > WorkflowTemplate").each(function(i,e) {
      // hard coded workflow name
      if ( $(this).attr("Name") == "Copy" ) {              
        var guid = $(this).find("WorkflowTemplateIdSet").attr("TemplateId");        
        if ( guid != null ) {
          workflowGUID = "{" + guid + "}";
          }
        }
      });
  }
});

var loadingImage = '#Loader' + ItemID;
var workflowTD = '#WorkflowTD' + ItemID;
  $(loadingImage).show();
  $().SPServices({
    operation: "StartWorkflow",
    item: ItemURL,
    templateId: workflowGUID,
    workflowParameters: "<root />",
    completefunc: function() {
      $(workflowTD).html("Workflow Started");
    }
  });
}
</script>
  • I use the object model to retrieve the GUID, but are you saying that it could be passing the wrong WF GUID to the StartWorkflow function? if (workflow.get_enabled() && workflow.get_allowManual()){ var workflowName = workflow.get_name(); if (workflowName == DesiredWorkflow){ var workflowGuid = '{' + workflow.get_id().toString() + '}'; //alert(workflowName + " ..... " + workflowGuid); RunWorkflow(ItemURL, ItemID, workflowGuid); } } – JuanTrev May 23 '13 at 15:07
  • I find it's much simpler to use the 2 SPServices functions than mixing and matching jQuery and COM code. I'll see if I can find an example where I've used it. – Eric Alexander May 23 '13 at 15:08
  • Edited with an example. – Eric Alexander May 23 '13 at 15:18
  • I am getting same error for the GetTemplatesForItem SPServices method call. Could this because of the SP site using SSL? I know I have had issues with the People Picker before and mixed content type messages, but some other SPService calls are fine (like the GetList call I used in the initial post). The same undefined xData.responseXML is being returned as before. – JuanTrev May 23 '13 at 18:35
  • I know the SPServices is running. If I put an alert in I am getting a response. But the responseXML is still undefined. completefunc: function (xData, Status) { alert("test"); } – JuanTrev May 23 '13 at 18:57
0

I think I found the answer, unfortunately. I believe the version played a huge role here. The solution is for a SharePoint Foundation environment. I believe the workflow.asmx web service is only available in SharePoint Server. This explains the 404 error I was seeing in Fiddler. Without upgrading the version, I am not sure if there is a workaround.

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.