3

I want to create and add a workflow programmatically to a list on SharePoint Online using JSOM (with sp.workflowservices.js).

First I created a test-workflow like this using SharePoint Designer 2013:
Test workflow
Then I saved the workflow as template, downloaded wsp from Site Assets and extracted workflow.xaml in order to get the XAML code:

<Activity mc:Ignorable="mwaw" x:Class="Test.MTW" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
          xmlns:local="clr-namespace:Microsoft.SharePoint.WorkflowServices.Activities"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
          xmlns:mwaw="clr-namespace:Microsoft.Web.Authoring.Workflow;assembly=Microsoft.Web.Authoring"
          xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Sequence>
        <Sequence>
            <mwaw:SPDesignerXamlWriter.CustomAttributes>
                <scg:Dictionary x:TypeArguments="x:String, x:String">
                    <x:String x:Key="InitBlock">InitBlock-7751C281-B0D1-4336-87B4-83F2198EDE6D</x:String>
                </scg:Dictionary>
            </mwaw:SPDesignerXamlWriter.CustomAttributes>
        </Sequence>
        <Flowchart StartNode="{x:Reference __ReferenceID0}">
            <FlowStep x:Name="__ReferenceID0">
                <mwaw:SPDesignerXamlWriter.CustomAttributes>
                    <scg:Dictionary x:TypeArguments="x:String, x:String">
                        <x:String x:Key="Next">4294967294</x:String>
                    </scg:Dictionary>
                </mwaw:SPDesignerXamlWriter.CustomAttributes>
                <Sequence>
                    <mwaw:SPDesignerXamlWriter.CustomAttributes>
                        <scg:Dictionary x:TypeArguments="x:String, x:String">
                            <x:String x:Key="StageAttribute">StageContainer-8EDBFE6D-DA0D-42F6-A806-F5807380DA4D
                            </x:String>
                        </scg:Dictionary>
                    </mwaw:SPDesignerXamlWriter.CustomAttributes>
                    <local:SetWorkflowStatus Disabled="False" Status="Stage 1">
                        <mwaw:SPDesignerXamlWriter.CustomAttributes>
                            <scg:Dictionary x:TypeArguments="x:String, x:String">
                                <x:String x:Key="StageAttribute">StageHeader-7FE15537-DFDB-4198-ABFA-8AF8B9D669AE
                                </x:String>
                            </scg:Dictionary>
                        </mwaw:SPDesignerXamlWriter.CustomAttributes>
                    </local:SetWorkflowStatus>
                    <Sequence DisplayName="Stage 1">
                        <local:WriteToHistory Message="Test"/>
                    </Sequence>
                    <Sequence>
                        <mwaw:SPDesignerXamlWriter.CustomAttributes>
                            <scg:Dictionary x:TypeArguments="x:String, x:String">
                                <x:String x:Key="StageAttribute">StageFooter-3A59FA7C-C493-47A1-8F8B-1F481143EB08
                                </x:String>
                            </scg:Dictionary>
                        </mwaw:SPDesignerXamlWriter.CustomAttributes>
                    </Sequence>
                </Sequence>
            </FlowStep>
        </Flowchart>
    </Sequence>
</Activity>

Then I deleted the workflow and tried creating it manually in console, using this code:

var xaml = ...; // Whole XAML code
var historyListId = ...; // History List ID. Already exists
var targetListId = ...; // My task list, normal tasks list

jQuery.getScript("/_layouts/15/sp.workflowservices.js", function () {
  var ctx = SP.ClientContext.get_current();
  var servicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(ctx, ctx.get_web());

  var definition = SP.WorkflowServices.WorkflowDefinition.newObject(ctx, ctx.get_web());
  definition.set_xaml(xaml);
  definition.set_displayName("Test");

  var deploymentService = servicesManager.getWorkflowDeploymentService();
  deploymentService.saveDefinition(definition);
  ctx.load(definition);

  ctx.executeQueryAsync(function () {
    deploymentService.publishDefinition(definition.get_id());

    ctx.executeQueryAsync(function () {
      var subscription = SP.WorkflowServices.WorkflowSubscription.newObject(ctx, ctx.get_web());
      subscription.set_name("Test");
      subscription.set_enabled(true);
      subscription.set_definitionId(definition.get_id());
      subscription.set_eventSourceId(targetListId);
      subscription.set_eventTypes(["ItemAdded"]);
      subscription.setProperty("TaskListId", targetListId);
      subscription.setProperty("HistoryListId", historyListId);
      subscription.setProperty("FormData", "");

      var subscriptionService = servicesManager.getWorkflowSubscriptionService();
      subscriptionService.publishSubscriptionForList(subscription, targetListId);

      ctx.executeQueryAsync(function () {
        console.log("done");
      });
    });
  });
});

This works fine, and I get done in my console.
However the workflow itself seems broken, and does not work.
The original workflow looked like this in designer:
Original workflow

while the newly created workflow looks like this (without type): New workflow

When I go into the workflow it seems to be missing lots of data:
New workflow info
And the Edit workflow-link is not clickable.
It does not seem to be properly linked to my task list, however if I open the task list directly it is listed under workflows:
Task list workflows

7

You need to load Id of the definition before creating subscription. Also subscriptionService.publishSubscriptionForList needs guid object instead of just GUID string. When we create List workflow using designer it sets few more properties RestrictTOScope and RestrictsToType.

While creating definition using code those properties are not configured hence Workflowtype is empty.

After creating definition using code, what we see on designer is Workflow Definition Template not the subscription, if you set restricttotype to list it will be reusable list workflow. if you set restrcttotype to 'List' and restricttoscope to Guid of the list it will set workflow type as list workflow.

Regarding Edit workflow link: make sure there is no new line character in xaml.

Updated code:

 function TestWorkflow() {
        var xaml = '<Activity mc:Ignorable="mwaw" x:Class="TestWF2.MTW" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:local="clr-namespace:Microsoft.SharePoint.WorkflowServices.Activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mwaw="clr-namespace:Microsoft.Web.Authoring.Workflow;assembly=Microsoft.Web.Authoring" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Sequence><Sequence><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="InitBlock">InitBlock-7751C281-B0D1-4336-87B4-83F2198EDE6D</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes></Sequence><Flowchart StartNode="{x:Reference __ReferenceID0}"><FlowStep x:Name="__ReferenceID0"><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="Next">4294967294</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes><Sequence><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="StageAttribute">StageContainer-8EDBFE6D-DA0D-42F6-A806-F5807380DA4D</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes><local:SetWorkflowStatus Disabled="False" Status="Stage 1"><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="StageAttribute">StageHeader-7FE15537-DFDB-4198-ABFA-8AF8B9D669AE</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes></local:SetWorkflowStatus><Sequence DisplayName="Stage 1"><local:WriteToHistory Message="Test" /></Sequence><Sequence><mwaw:SPDesignerXamlWriter.CustomAttributes><scg:Dictionary x:TypeArguments="x:String, x:String"><x:String x:Key="StageAttribute">StageFooter-3A59FA7C-C493-47A1-8F8B-1F481143EB08</x:String></scg:Dictionary></mwaw:SPDesignerXamlWriter.CustomAttributes></Sequence></Sequence></FlowStep></Flowchart></Sequence></Activity>';
        var historyListId = "{...}"; // History List ID. Already exists

        var tasklistId = "{...}";
        jQuery.getScript("/_layouts/15/sp.workflowservices.js", function () {
            var ctx = SP.ClientContext.get_current();
            var servicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(ctx, ctx.get_web());

            var definition = SP.WorkflowServices.WorkflowDefinition.newObject(ctx, ctx.get_web());
            definition.set_xaml(xaml);
            definition.set_displayName("Test1234");
            definition.set_restrictToType('List');
            var deploymentService = servicesManager.getWorkflowDeploymentService();
            deploymentService.saveDefinition(definition);
            ctx.load(definition, "Id");

            var targetList = ctx.get_web().get_lists().getByTitle('Documents');
            ctx.load(targetList, 'Id');

            ctx.executeQueryAsync(function () {
                deploymentService.publishDefinition(definition.get_id());

                ctx.executeQueryAsync(function () {
                    var subscription = new SP.WorkflowServices.WorkflowSubscription(ctx);

                    subscription.set_name("Test1234");
                    subscription.set_enabled(true);
                    subscription.set_definitionId(definition.get_id());
                    subscription.set_eventSourceId(targetList.get_id());
                    subscription.set_eventTypes(["ItemAdded"]);
                    subscription.setProperty("TaskListId", tasklistId);
                    subscription.setProperty("HistoryListId", historyListId);
                    subscription.setProperty("FormData", "");

                    var subscriptionService = servicesManager.getWorkflowSubscriptionService();
                    subscriptionService.publishSubscriptionForList(subscription, targetList.get_id());

                    ctx.executeQueryAsync(function () {
                        console.log("done");
                    });
                });
            });
        });
    }
  • Dude! Thanks, it works, awesome! All I had to do was to add definition.set_restrictToType("List");definition.set_restrictToScope(targetListId); to my original code. Doesn't seem to need new SP.Guid(..), at least not on online, also the Id will be loaded when I load the whole definition. Seems you are correct about the newlines in XAML – eirikb Oct 14 '15 at 8:51

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.