SharePoint 2013 Workflow - Integrating a Custom Association Form

Overview

In SharePoint 2013, the integration of custom forms like Association form, initiation form etc, is different from the way we do it in SharePoint 2010. In 2010 we can use either a InfoPath or ASPX pages. however in SharePoint 2013, per the know issues article, there are no more InfoPath based workflow forms. For the workflow based on SharePoint Designer 2013 and Windows Azure Workflow, SharePoint Designer creates ASPX forms instead of InfoPath forms that were created by SharePoint 2010 workflows. If you want to customize the form, you can click it from the forms slab in workflow summary page to show a generic ASPX page editor

 

Visual Studio 2012 also provides a rich set of capabilities to create Association and Initiation forms.

 

The following are the very important capabilities/features added to SharePoint workflow while creating custom workflows using Visual Studio 2012.

  1. SharePoint 2013 introduced a rich set of client-side object mode (CSOM) based workflow API that's can be fully leveraged in VS2012
  2. VS2012 Provides a standard Workflow Association and Initiation form templates (ASP.Net form based) out of the box (When SharePoint 2013 templates are installed)

In this article we will be covering the complete set of steps involved in creating a custom workflow form and associating it to the workflow.

Understanding the need of Association Form:

Association and initialization forms are displayed for users to fill out before any workflow is actually started. You can use these forms to enable users to set parameters and other information for the workflow before it starts. In case if there are no custom properties/parameters needs to be associated with the workflow, the association form is not mandatory.

Preparing workflows to be accessed from association forms

In order to pass a parameter/property from the association form to the workflow, the workflow must implement/use an activity called GetConfigurationValue, which is capable/responsible for retrieving the value passed as an association data.

The activity GetConfigurationValue can be located on Runtime group of workflow activities tool box .

 

 

Upon adding the activity to the workflow, associate the activity with a variable declared at the workflow level.

 

 

You can create as many parameters as required in the same way with appropriate GetConfigurationValue Activity associated with a valid string variable in the workflow.

 

Upon completion of this change, we are good to go-ahead and add the association form and make necessary changes.

Adding an Association Form

To add an association form to any workflow perform the following steps.

  • Right click the workflow folder and select "Add" - "New Item" from the context menu.

  • On Add new Item Dialog, select "Workflow Association Form" on Office/SharePoint group

 

  • This will add a new Association form like the one attached to the workflow with default placeholders (2 text boxes, 1 date control, save and cancel button) and basic Ready to Customize CSOM code that could be a good starting point to build (customize) it with your own logic based on your business requirements.

Changes on workflow Elements.Xml

Upon adding the association form, please ensure if the elements.xml associated with the workflow is updated with the entries highlighted below.

<?xml version="1.0" encoding="utf-8" ?>

<Elements xmlns="https://schemas.microsoft.com/sharepoint/">

  <Module Name="Approval" Url="wfsvc/73C27777198F43B4A7C0FE6753ADA4C4">

    <File Url="Workflow.xaml" Type="GhostableInLibrary" Path="Approval\Workflow.xaml" Level="Published" DoGUIDFixUp="TRUE">

      <Property Name="ContentTypeId" Value="0x01002A2479FF33DD4BC3B1533A012B653717004C4A72D4775DB04F8979AE7A4A568F20" />

      <Property Name="ContentType" Value="WorkflowServiceDefinition" />

      <Property Name="_ModerationStatus" Value="0" />

      <Property Name="FileDirRef" Value="wfsvc/73C27777198F43B4A7C0FE6753ADA4C4" />

      <Property Name="FSObjType" Value="0" />

      <Property Name="FileLeafRef" Value="workflow.xaml" />

      <Property Name="isReusable" Value="true" />

      <Property Name="RequiresInitiationForm" Value="false" />

      <Property Name="RequiresAssociationForm" Value="true" />

      <Property Name="WSGUID" Value="{73C27777-198F-43B4-A7C0-FE6753ADA4C4}" />

      <Property Name="WSPublishState" Value="3" />

      <Property Name="WSDisplayName" Value="Approval" />

      <Property Name="WSDescription" Value="Approval" />

      <Property Name="RestrictToType" Value="List" />

      <Property Name="DisableAutoStartCreate" Value="false" />

      <Property Name="DisableManualStart" Value="false" />

      <Property Name="AssociationUrl" Value="wfsvc/73C27777198F43B4A7C0FE6753ADA4C4/Approval/AssociationForm.aspx" />

    </File>

    <File Path="Approval\AssociationForm.aspx" Url="Approval/AssociationForm.aspx" />

  </Module>

  <ListInstance FeatureId="{2c63df2b-ceab-42c6-aeff-b3968162d4b1}"

                TemplateType="4501"

                Title="wfsvc"

                Description="This list instance is used by SharePoint to keep track of workflows. Do not modify."

                Url="wfsvc"

                RootWebOnly="FALSE" />

</Elements>

Customizing an Association Form

By this time we will have a Ready to Customize association from its now time to go and customize the same. 

The form will be enabled with the following JavaScript method with some default logic.

 

// ---------- Save workflow association ----------

function associateWF(state, pauseFunction) {

if (complete != 0)

return complete;

var historyListId = "";

var taskListId = "";

var metadata = new Object();

// Get form input values and set workflow in-argument values

var strInputValue = document.getElementById("strInput").value;

if (strInputValue) {

metadata['strArg'] = strInputValue;

}

var intInputValue = document.getElementById("intInput").value;

if (intInputValue) {

var intValue = parseInt(intInputValue);                               

if (intValue)

metadata['intArg'] = intValue;

}

we can customize this logic to retrieve the content from the modified form elements and might make it something like the following.

// ---------- Save workflow association ----------

function associateWF(state, pauseFunction) {

if (complete != 0)

return complete;

var historyListId = "";

var taskListId = "";

var metadata = new Object();

// Get form input values and set workflow in-argument values

var html = $("#ctl00_PlaceHolderMain_spApprovers_upLevelDiv");

var approvers = $("#divEntityData", html).attr("key");

if (approvers && approvers.length > 0) {

metadata['Approvers'] = approvers;

}

else {

       alert("Approvers field cannot be empty"); return;

}

var intDurationDays = document.getElementById("txtDurationDays").value;

if (intDurationDays) {

var intValue = parseInt(intDurationDays);

if (intValue && intValue > 0) {

metadata['Duration'] = intValue;

}

}

var boolFirstApproval = document.getElementById("chkFirstApproval");

 if (boolFirstApproval) {

metadata['EndonFirstApproval'] = boolFirstApproval.checked;

}

In addition, the OOB method integrates the following logic as well.

  1. Get form input values and set workflow in-argument values
  2. Sets History list id. If its new history list, creates new history list
  3. Sets task list id. If its new task list, creates new task list
  4. Checks, if task list contains the OOTB SharePoint 2013 Workflow Task content type
  5. Associates the workflow to selected triggering option selected on the previous workflow screen (Manual, Item Added, Item Updated)
  6. If workflow association exists, then we will update its subscription information. Otherwise, it's a new association, and we will add the new subscription.
  7. Publish the workflow

Editing an existing workflow - Customizing the association form to populate the association parameters

The Association form will not provide any option of populating the association parameter when editing an existing workflow. however this can be achieved by adding a new function and calling it from the function setHeader() which gets executed upon load. For retrieving the subscription info, will have to create an instance of the workflow manger and call the method getSubscription by passing subscription id as an input parameter. The subscription id would be available pre set upon the page load, there is no need to retrieve the subscription id manually.

Upon completion your association form is ready to go and get deployed.

Samples

Sample of a customized association form can be found here.

Sample Approval workflow with a customized association form can be downloaded from here.