Embedded Forms Reference

Introduction

This reference covers the features of the Camunda BPM Forms SDK. The Forms SDK simplifies the implementation of user task forms in HTML5 / JavaScript based Applications. The Forms SDK itself is written in JavaScript and can be added to any JavaScript based Application.

Features

The Forms SDK provides the following features:

  • Form handling: attach to a form existing in the DOM or load a form from a URL.
  • Variable handling: load and submit variables used in the form.
  • Script handling: execute custom JavaScript in Forms
  • Angular JS Integration: The Forms SDK optionally integrates with AngularJS to take advantage of AngularJS form validation and other AngularJS goodies.

The following is a simple example of a form with two input fields binding to process variables CUSTOMER_ID and CUSTOMER_REVENUE:

<form>

  <label for="customerId">Customer Id:</label>

  <input type="text" id="customerId"
         cam-variable-name="CUSTOMER_ID"
         cam-variable-type="String">

  <label for="customerRevenue">Customer Revenue:</label>

  <input type="text" id="customerRevenue"
         cam-variable-name="CUSTOMER_REVENUE"
         cam-variable-type="Double">

</form>

Anti Features

The Forms SDK is intended to be lean and small. By design it is not concerned with things like

  • Form Validation: Instead, integrate with existing frameworks such as AngularJS.
  • Components / Widgets: Instead, integrate nicely with existing component libraries like jQuery UI, Angular UI, ...
  • Form Generation: Instead, allow users to leverage the complete power of HTML and JavaScript to implement complex forms.

Overview

The Forms SDK provides a set of directives which simplify working with process variables in an HTML form. These directives work on most of the HTML controls and allow users to declaratively fetch variables from the process engine and have their values written to and read from input fields.

If an HTML control is not supported, you need to write custom JavaScript.

The cam-variable-name Directive

The cam-variable-name directive allows providing the name of a process / task / case variable. If the directive is discovered on an HTML control, the value of the variable is fetched from the server and written to the control.

<input type="text"
       cam-variable-name="CUSTOMER_ID">

The cam-business-key Directive

The cam-business-key is aimed to be used on a free text input field in order to define a businessKey at the start of a process.
This attribute is only relevant when the form is aimed to start a process.

<input type="text"
       cam-business-key>

See also: Setting the business key using Javascript

AngularJS support and cam-variable-name

If you use the AngularJS integration, the cam-variable-name directive will automatically bind the input to the model in case no binding is provided by the user.

The following two markup examples have the same semantics:

<input type="text"
       cam-variable-name="CUSTOMER_ID">

is the same as

<input type="text"
       cam-variable-name="CUSTOMER_ID"
       ng-model="CUSTOMER_ID">

If the user provides a customer ng-model binding, it is respected:

<input type="text"
       cam-variable-name="CUSTOMER_ID"
       ng-model="customerId">

Current value: {{customerId}}

The cam-variable-type Directive

The cam-variable-type directive allows specifying the type of a process / task / vase variable. This is required if the variable does not yet exist.

The following markup creates a text input field bound to a variable of type Double:

<input type="text"
       cam-variable-name="INVOICE_AMOUNT"
       cam-variable-type="Double">

Supported Variable Types

See the section on variable types for a list of variable types which are supported out of the box.

AngularJS support and cam-variable-type

The cam-variable-type directive can be used as validation directive:

<input type="text"
       name="invoiceAmount"
       cam-variable-name="INVOICE_AMOUNT"
       cam-variable-type="Double">

<span ng-show="myForm.invoiceAmount.$error.camVariableType">
  Input must be a 'Double'.
</span>

Text Inputs

Single line text inputs are <input type="text"> controls. Single line text inputs are the most common input field and allow the user to provide values for different data types.

Binding Text Input to a Process Variable

A text input can be bound to a process variable using the cam-variable-type and cam-variable-name directives:

<input type="text"
       cam-variable-name="CUSTOMER_ID"
       cam-variable-type="String" />

In the example above, the text input field is bound to the variable named CUSTOMER_ID of type String.

Supported Variable Types for Text Inputs

A text input field supports multiple variable types.

Binding to existing variables: Note that if you bind the input field to an existing variable, the type of the variable is provided by the process engine and the cam-variable-type directive is not required.

String

In order to bind the input field to a String variable, the directive cam-variable-type="String" must be used.

Example:

<input type="text"
       cam-variable-name="CUSTOMER_ID"
       cam-variable-type="String" />

Trimming: Note that the value of the String variable is trimmed before it is submitted to the process engine: leading and trailing whitespace is removed.

Integer

In order to bind the input field to a Java Integer variable, the directive cam-variable-type="Integer" must be used.

Example:

<input type="text"
       cam-variable-name="CUSTOMER_AGE"
       cam-variable-type="Integer" />

Long

In order to bind the input field to a Java Long variable, the directive cam-variable-type="Long" must be used.

Example:

<input type="text"
       cam-variable-name="CUSTOMER_REVENUE"
       cam-variable-type="Long" />

Short

In order to bind the input field to a Java Short variable, the directive cam-variable-type="Short" must be used.

Example:

<input type="text"
cam-variable-name="CUSTOMER_REVENUE"
cam-variable-type="Short" />

Double

In order to bind the input field to a Java Double variable, the directive cam-variable-type="Double" must be used.

Example:

<input type="text"
cam-variable-name="CUSTOMER_REVENUE"
cam-variable-type="Double" />

Textareas

Textareas are HTML <textarea> elements of the form

<textarea></textarea>

Binding a Textarea to a Process Variable

A textarea input can be bound to a process variable using the cam-variable-type and cam-variable-name directives:

<textarea cam-variable-name="CUSTOMER_ADDRESS"
          cam-variable-type="String">
</textarea>

In the example above, the textarea is bound to the variable named CUSTOMER_ADDRESS of type String.

Supported Variable Types for Textareas

The textarea supports the same variable types as the single line text input <input type="text"></input>.

Date Inputs

Date input is supported using a <input type="text"> control.

Binding to a Process Variable

In order to bind the input field to a Java Date variable, the directive cam-variable-type="Date" must be used.

Example:

<input type="text"
       cam-variable-name="CONTRACT_START_DATE"
       cam-variable-type="Date" />

Date Format

Currently only the ISO Date Format yyyy-MM-dd'T'HH:mm:ss is supported. Example value: 2013-01-23T13:42:42

Using a Date Picker

The Form SDK itself does not provide any custom components of widgets. As such it also does not provide a date picker. However, you are able to integrate third party libraries providing such widgets.

Inside Camunda Tasklist, datepicker support is provided through Angular UI.

You can use the Angular UI datepicker directive to offer a datepicker for the date input field. The complete markup of the input field including the datepicker button is shown below.

<p class="input-group">

  <input type="text"
       cam-variable-name="CONTRACT_START_DATE"
       cam-variable-type="Date"
       class="form-control"
       datepicker-popup="yyyy-MM-dd'T'HH:mm:ss"
       is-open="dateFieldOpened" />

  <span class="input-group-btn">
    <button type="button"
            class="btn btn-default"
            ng-click="open($event)">
      <i class="glyphicon glyphicon-calendar"></i>
    </button>
  </span>
</p>

In addition to the HTML markup, the following JavaScript must be included in the form file (see Custom JavaScript):

<script cam-script type="text/form-script">
  $scope.open = function($event) {
    $event.preventDefault();
    $event.stopPropagation();

    $scope.dateFieldOpened = true;
  };
</script>

The attributes of the datepicker component are explained below:

Additional attributes of the input element:

  • datepicker-popup="yyyy-MM-dd'T'HH:mm:ss": This attribute sets the format of the date which is returned by the datepicker. It must be the ISO Date Format.
  • is-open="dateFieldOpened": This attribute contains the name of the variable, which indicates the open status of the datepicker. It must be the same variable, which is set to true in the open function in the JavaScript snippet. If a form contains multiple datepickers, they must have different values for this attribute.

Attributes of the datepicker button:

  • ng-click="open($event)": This attribute contains the name of the function which is called when the datepicker button is clicked. It must be the function name of the JavaScript snippet which sets the is-open variable to true. If a form contains multiple date pickers, they must have different function names, or the name of the is-open variable must be passed to the function.

Boolean Inputs

Checkbox

Checkboxes are HTML <input type="checkbox"> controls. Checkbox controls can be used for boolean variable types.

Binding a Checkbox to a Process Variable

A checkbox input can be bound to a process variable using the cam-variable-type and cam-variable-name directives:

<input type="checkbox"
       cam-variable-name="IS_VIP_CUSTOMER"
       cam-variable-type="Boolean" />

In the example above, the checkbox is bound to the variable named IS_VIP_CUSTOMER of type Boolean.

Supported Variable Types for Checkboxes

The checkbox input field only supports boolean variable types. A checked checkbox corresponds to the value true, an unchecked checkbox corresponds to the value false.

Boolean Select Box

In order to bind a <select> box to a Java Boolean variable, the directive cam-variable-type="Boolean" must be used.

Example:

<select cam-variable-name="APPROVED"
        cam-variable-type="Boolean">
  <option value="true">Yes</option>
  <option value="false">No</option>
</select>

Boolean text Input

In order to bind a text input field to a Java Boolean variable, the directive cam-variable-type="Boolean" must be used.

Text input fields of type Boolean accept the following string values:

  • true
  • false

Meaning that the user has to type the words "true" or "false" into the text input field.

Example:

<input type="text"
       cam-variable-name="IS_VIP_CUSTOMER"
       cam-variable-type="Boolean" />

Selects

Select boxes are HTML controls of the form

<select></select>

Binding to a Process Variable

A select box can be bound to a process variable using the cam-variable-name directive:

<select cam-variable-name="foo"
        cam-variable-type="String">
  <option>bar</option>
  <option>zar</option>
</select>

Supported Variable Types

The select box supports the same value types as <input type="text">.

Populating the Options from a Variable

The <option> entries can be populated using a variable. The name of the variable can be provided using the cam-choices directive:

<select cam-variable-name="PRODUCT_TYPE"
        cam-variable-type="String"
        cam-choices="AVAILABLE_PRODUCT_TYPES">
</select>

The directive cam-choices expects the values to be a List or Map (Object). In case of a Map (Object), the keys of the map are used as values of the options. java.util.Map and java.util.List are supported but must be serialized as JSON:

Map<String, String> productTypes = new HashMap<String, String>();
productTypes.put("001", "Notebook");
productTypes.put("002", "Server");
productTypes.put("003", "Workstation");

execution.setVariable("AVAILABLE_PRODUCT_TYPES",  
  objectValue(customerData)
    .serializationDataFormat(SerializationDataFormats.JSON)
    .create());

Would be rendered as

<select cam-variable-name="PRODUCT_TYPE"
        cam-variable-type="String"
        cam-choices="AVAILABLE_PRODUCT_TYPES">
  <option value="001">Notebook</option>
  <option value="002">Server</option>
  <option value="003">Workstation</option>
</select>

Hidden Input Fields

Hidden input elements are HTML

<input type="hidden"></input>

controls. They are not displayed in the form, but can be used to retrieve values to be used in the context of the form (e.g., using Angular bindings).

Binding a Hidden Element to a Process Variable

A hidden input can be bound to a process variable using the cam-variable-type and cam-variable-name directives:

<input type="hidden"
       cam-variable-name="CUSTOMER_ID"
       cam-variable-type="String"
       value="testuser" />

In the example above, the hidden input field is bound to the variable named CUSTOMER_ID of type String and contains the value testuser.

Supported Variable Types for Hidden Elements

The hidden input field supports the same variable types as the single line text input <input type="text"></input>.

File Input Fields

Note: File Upload is not supported for Internet Explorer 9.

File input elements are HTML

<input type="file"></input>

controls. They allow users to upload files, which will be stored as a process instance variable of the type Bytes. Larger files will take longer to process and may crash the browser, so there is a soft file size limit of 5MB. You can overwrite this limit using the cam-max-filesize directive. To upload larger files without freezing the browser, see the custom javascript section.

The file input element can not be used to download previously uploaded files. To provide download links for files, see the download example in the custom javascript section.

Uploading Files

Files can be uploaded using the cam-variable-name and cam-variable-type directives:

<input type="file"
       cam-variable-name="INVOICE_DOCUMENT"
       cam-variable-type="Bytes"
       cam-max-filesize="10000000" />

In the example above, the user can upload a document with a maximum filesize of 10MB. The uploaded file will be stored as process instance variable with the name INVOICE_DOCUMENT.

Supported Variable Types for Input Elements

The file input type supports variables of type Bytes only. The directive cam-variable-type="Bytes" must be used.

The cam-script Directive

It is possible to use custom JavaScript in embedded forms.

Custom JavaScript can be added to a form by using a <script> tag and adding the cam-script directive:

<form role="form">

  <script cam-script type="text/form-script">
  // custom script goes here
  </script>

</form>

Available API

Inside a form script, the following built-in variables and functions are available:

camForm

The camForm variable is an instance of the CamSDK.Form class and is the primary access point to the form API and allows definition of event handers for participation in the form lifecycle:

<form role="form">
  ...
  <script cam-script type="text/form-script">
    var variableManager = camForm.variableManager;

    camForm.on('variables-fetched', function() {
      // access to all process variables after the form has loaded
      console.log(variableManager.variables);
    });
  </script>

</form>

$scope

Only available with AngularJS integration.

Provides access to the current AngularJS scope:

<form role="form">

  <input type="text"
         cam-variable-name="CUSTOMER_ID"
         cam-variable-type="String"
         ng-model="customerId" />

  <script cam-script type="text/form-script">
    camForm.on('variables-applied', function() {
      // the input field is bound to $scope.customerId
      $scope.customerId = "some-id";
    });
  </script>

</form>

inject()

Only available with AngularJS integration.

<form role="form">

  <script cam-script type="text/form-script">
    inject([ '$scope', '$http', function($scope, $http) {
      camForm.on('form-loaded', function() {
        // use injected $http service for making requests
      });
    }]);
  </script>

</form>

Participating in the Form Lifecycle

It is possible to participate in the lifecycle of the form. See Form Lifecycle and Events for more details.

Fetching additional Variables

When loading the form, the values of all variables used in the form will be fetched from the backend. This means that the form SDK will only fetch those variables which are actually used in the form. The most convenient way for using a variable is the cam-variable-name directive. However, there are some situations where directive-based usage is inconvenient. In such situations it is useful to declare additional variables programmatically:

<form role="form">

  <div id="my-container"></div>

  <script cam-script type="text/form-script">
    var variableManager = camForm.variableManager;

    camForm.on('form-loaded', function() {
      // this callback is executed *before* the variables are loaded from the server.
      // if we declare a variable here, its value will be fetched as well
      variableManager.fetchVariable('customVariable');
    });

    camForm.on('variables-fetched', function() {
      // this callback is executed *after* the variables have been fetched from the server
      var variableValue = variableManager.variableValue('customVariable');
      $( '#my-container', camForm.formElement).textContent(variableValue);
    });
  </script>

</form>

Submitting additional Variables

Similar to fetching additional variables using a script, it is also possible to add additional variables to the submit:

<form role="form">

  <script cam-script type="text/form-script">
    var variableManager = camForm.variableManager;

    camForm.on('submit', function() {
      // this callback is executed when the form is submitted, *before* the submit request to
      // the server is executed

      // creating a new variable will add it to the form submit
      variableManager.createVariable({
        name: 'customVariable',
        type: 'String',
        value: 'Some Value...',
        isDirty: true
      });

    });
  </script>

</form>

Implementing Custom Fields

The following is a small usage example which combines some of the features explained so far. It uses custom JavaScript to implement a custom interaction with a form field which does not use any cam-variable-* directives.

It shows how custom scripting can be used for

  • declaring a variable to be fetched from the backend,
  • writing the variable's value to a form field,
  • reading the value upon submit.
<form role="form">

  <!-- custom control which does not use cam-variable* directives -->
  <input type="text"
         class="form-control"
         id="customField">

  <script cam-script type="text/form-script">
    var variableManager = camForm.variableManager;
    var customField = $('#customField', camForm.formElement);

    camForm.on('form-loaded', function() {
      // fetch the variable 'customVariable'
      variableManager.fetchVariable('customVariable');
    });

    camForm.on('variables-fetched', function() {
      // value has been fetched from the backend
      var value = variableManager.variableValue('customVariable');
      // write the variable value to the form field
      customField.val(value);
    });

    camForm.on('submit', function(evt) {
      var fieldValue = customField.val();
      var backendValue = variableManager.variable('customVariable').value;

      if(fieldValue === backendValue) {
        // prevent submit if value of form field was not changed
        evt.submitPrevented = true;

      } else {
        // set value in variable manager so that it can be sent to backend
        variableManager.variableValue('customVariable', fieldValue);
      }
    });
  </script>

</form>

The above example uses jQuery for interacting with the HTML controls. If you use AngularJS, you can also populate the $scope in the variables-fetched callback and read the values from the $scope in the submit callback:

<form role="form">

<!-- custom control which does not use cam-variable* directives
     but binds to the angular scope -->
<input type="text"
       class="form-control"
       id="customField"
       ng-model="customerId">

<script cam-script type="text/form-script">
  var variableManager = camForm.variableManager;

  $scope.customerId = null;

  camForm.on('form-loaded', function() {
    // fetch the variable 'customVariable'
    variableManager.fetchVariable('customVariable');
  });

  camForm.on('variables-fetched', function() {
    // value has been fetched, bind to $scope.customerId
    $scope.customerId = variableManager.variable('customVariable').value;
  });

  camForm.on('submit', function(evt) {
    // set value in variable manager so that it can be sent to backend
    variableManager.variableValue('customVariable', $scope.customerId);
  });
</script>

</form>

Debugging Scripts

If a form script is loaded using an XHR from a web server, it is executed using eval(). In order to debug it, you need to use browser-specific debugger extensions.

Debugging Form Scripts in Google Chrome

If you are using the Google Chrome debugger, you can add the debugger; directive to the source code of the script:

<form role="form">

  <script cam-script type="text/form-script">
    debugger;
  </script>

</form>

Generating a Business Key

The following examples shows how you can generate a business key using Javascript:

<form role="form">
  <script cam-script type="text/form-script">

    camForm.on('submit', function() {
      camForm.businessKey = 'some-generated-value';
    });

  </script>

</form>

As you can see, you can set the businessKey variable on the camForm object. The value you set will be submitted in the start process instance request.

Note that the business key can only be set when a process instance is started, not when completing a task.

Examples

The following examples show example scenarios of custom JavaScript in embedded forms.

Load Additional Resources

This example includes an image, which is located in the contextPath of the form (i.e., in the same directory). The URL of the image is retrieved via the task form key method of the REST API:

<form role="form">
  <script cam-script type="text/form-script">
    inject(['$http', 'Uri', function($http, Uri) {
      camForm.on('form-loaded', function() {
        $http.get(Uri.appUri("engine://engine/:engine/task/" + camForm.taskId + "/form")).success(function(result){
          $scope.contextPath = result.contextPath;
        });
      });
    }]);
  </script>

  <img ng-src="{{contextPath}}/image.png" />

</form>

This example provides a download link for the file stored in the byte variable INVOICE_DOCUMENT. First, the process instance id of the task is retrieved to then access the id of the INVOICE_DOCUMENT variable. In Google Chrome and Mozilla Firefox you can also specify the filename with the download attribute in the <a> tag. In this example, the file name is retrieved from the process variable INVOICE_DOCUMENT_FILENAME.

<form role="form">
  <script cam-script type="text/form-script">
    inject(['$http', 'Uri', function($http, Uri) {
      camForm.on('form-loaded', function() {

        // get the download link
        $http.get(Uri.appUri('engine://engine/:engine/task/' + camForm.taskId)).success(function(result){
          $http.get(Uri.appUri('engine://engine/:engine/variable-instance/?variableName=INVOICE_DOCUMENT&processInstanceIdIn=' + result.processInstanceId)).success(function(result){
            $scope.downloadLink = Uri.appUri('engine://engine/:engine/variable-instance/' + result[0].id + '/data');
          });
        });

        // get the filename
        camForm.variableManager.fetchVariable('INVOICE_DOCUMENT_FILENAME');
      });

      camForm.on('variables-fetched', function() {
        $scope.INVOICE_DOCUMENT_FILENAME = camForm.variableManager.variableValue('INVOICE_DOCUMENT_FILENAME');
      });
    }]);
  </script>

  <a ng-href="{{downloadLink}}" download="{{INVOICE_DOCUMENT_FILENAME}}" target="_blank">Download File</a>

</form>

Store filename for uploaded file

This example shows how to store the filename of an uploaded file (INVOICE_DOCUMENT) in the process variable INVOICE_DOCUMENT_FILENAME.

<form role="form">
  <script cam-script type="text/form-script">
    camForm.on('submit', function(evt) {
      camForm.variableManager.createVariable({
        name: 'INVOICE_DOCUMENT_FILENAME',
        type: 'String',
        value: camForm.formElement.find('[cam-variable-name="INVOICE_DOCUMENT"]')[0].files[0].name
      });
    });
  </script>

  <input type="file"
         cam-variable-name="INVOICE_DOCUMENT"
         cam-variable-type="Bytes"
         cam-max-filesize="10000000" />
</form>

Upload Large Files

This example contains a file input element and the script to send it to the server. In contrast to the file input element of the Forms SDK, this example can handle large files, but it also has some drawbacks:

  • Can not be used in the start form of a process (no process instance id exists at this time)
  • Does not take part in the form lifecycle (files could be saved even if the form is not submitted)
  • Can only save one file at a time

This example first retrieves the process instance id of the task for the form. It then registers an upload function, which, when executed, uploads the data as a process instance variable with the name uploadedFile

<form role="form">
  <input id="fileUpload"
         type="file" />
  <button ng-click="upload()">Upload</button>

  <script cam-script type="text/form-script">
    inject(['$http', 'Uri', function($http, Uri) {
      camForm.on('form-loaded', function() {
        $http.get(Uri.appUri('engine://engine/:engine/task/' + camForm.taskId)).success(function(result){
          $scope.upload = function() {
            var formData = new FormData();
            formData.append('data', document.getElementById('fileUpload').files[0]);
            $http.post(Uri.appUri('engine://engine/:engine/process-instance/' + result.processInstanceId + '/variables/uploadedFile/data'), formData, {
                transformRequest: angular.identity,
                headers: {'Content-Type': undefined}
            });
          };
       });
      });
    }]);
  </script>
</form>

Events

  1. The form is parsed, and variable names are collected from the markup. This means that directives like cam-variable-name are evaluated and the resulting variables are declared in the variableManager.

    Events:

    • form-loaded is fired after the form has been parsed, and all form directives have been evaluated.
  2. In the second phase, a request is made to the server to gather the values of the variables declared in the variable manager.

    Events:

    • variables-fetched is fired after the request returns and the values of the variables have been merged into the variableManager.
  3. If a saved state of the form exists, the variable values are replaced with the saved state.

    Events:

    • variables-restored is fired after the saved values of the variables have been merged with the values in the variableManager
  4. Next, the variables are applied to the form controls. This means that HTML input fields and select boxes are populated with the variable values present in the variableManager.

    Events:

    • variables-applied is fired after the values of the variables have been applied to the form controls.
  5. The user interacts with the form. In this phase no events are fired.

  6. The user can save the form, which causes the current values of the variables to be stored in the localStorage. If the user comes back to the form later, the values are restored.

    Events:

    • store is fired before the values of the variables are written to the localStorage. An event handler may prevent the values from being stored.
    • variables-stored is fired after the values are written to the localStorage.
  7. Finally, the form is submitted.

    Events:

    • submit is fired before the submit request is sent to the server. An event handler may prevent the form from being submitted by setting the property submitPrevented true.

    • submit-success is fired after the server successfuly treated the submission

    • submit-failed is fired after the server failed at treating the submission or when a network error happened

Registering event listeners

Event listeners can be registered from custom JavaScript:

<form role="form" name="form">

  <script cam-script type="text/form-script">

    camForm.on('form-loaded', function() {
      // handle form loaded
    });

    camForm.on('variables-fetched', function() {
      // handle variables fetched
    });

    camForm.on('variables-restored', function() {
      // handle variables restored
    });

    camForm.on('variables-applied', function() {
      // handle variables applied
    });

    camForm.on('store', function(evt) {
      // handle store
      // may prevent the store from being executed
      evt.storePrevented = true;
    });

    camForm.on('variables-stored', function() {
      // handle variables stored
    });

    camForm.on('submit', function(evt) {
      // handle submit
      // may prevent the submit from being executed:
      evt.submitPrevented = true;
    });

    camForm.on('submit-success', function() {
      // handle submit-success
    });

    camForm.on('submit-error', function(evt, res) {
      // handle submit-error:
      var error = res[0];
    });

  </script>

</form>

Fetching a Serialized Java Object

This section explains how to work with serialized Java Objects in embedded task forms.

NOTE: Out of the box, you can only work with Java Objects which are serialized in JSON format If Java Classes are serialized using JAX-B, you need to add custom XML parsing and writing logic to the embedded form. Java Objects serialized using Java Serialization cannot be used in forms.

The Form SDK will only fetch those variables which are actually used in a form. Since a Complex Java Object is usually not bound to a single input field, we cannot use the cam-variable-name directive. We thus need to fetch the variable programatically:

<script cam-script type="text/form-script">
  camForm.on('form-loaded', function() {
    // tell the form SDK to fetch the variable named 'invoiceData'
    camForm.variableManager.fetchVariable('invoiceData');
  });
  camForm.on('variables-fetched', function() {
    // work with the variable (bind it to the current AngularJS $scope)
    $scope.invoiceData = camForm.variableManager.variableValue('invoiceData');
  });
</script>

Creating a new Serialized Java Object

In case the variable does not yet exist (for instance in a Start Form), you have to create the variable and specify the necessary meta data in order for the process engine to correctly handle the variable as Java Object.

<script cam-script type="text/form-script">

  var dataObject = $scope.dataObject = {};

  camForm.on('form-loaded', function() {

    // declare variable 'customerData' incuding metadata for serialization
    camForm.variableManager.createVariable({
      name: 'customerData',
      type: 'Object',
      value: dataObject,
      valueInfo: {
        // indicate that object is serialized as json
        serializationDataFormat: 'application/json',
        // provide classname of java object to map to
        objectTypeName: 'org.camunda.bpm.example.CustomerData'
      }
    });

  });

</script>

Full Example

A full example of this feature can be found in the Camunda BPM Examples Repository.

Creating a new JSON variable

You can use JSON objects in your embedded forms. In order to persist this data in the process instance, you have to explicitely create the variable in the variableManager. This code-snippet creates the variable customer.

<script cam-script type="text/form-script">
  var customer = $scope.customer = {
    firstName: 'John',
    lastName: 'Doe'
  };

  camForm.on('form-loaded', function() {

    // declare a 'json' variable 'customer'
    camForm.variableManager.createVariable({
      name: 'customer',
      type: 'json',
      value: customer
    });
  });
</script>

Fetching a JSON variable

The Form SDK will only fetch those variables which are actually used in a form. Since a JSON object is usually not bound to a single input field, we cannot use the cam-variable-name directive. We thus need to fetch the variable programatically:

<script cam-script type="text/form-script">
  camForm.on('form-loaded', function() {
    // tell the form SDK to fetch the variable named 'customer'
    camForm.variableManager.fetchVariable('customer');
  });
  camForm.on('variables-fetched', function() {
    // work with the variable (bind it to the current AngularJS $scope)
    $scope.customer = camForm.variableManager.variableValue('customer');
  });
</script>

After that, you can work with the JSON object in your form, e.g. use it in input fields:

<input type="text" ng-model="customer.firstName" required />
<input type="text" ng-model="customer.lastName" required />

Full Example

A full example of this feature can be found in the Camunda BPM Examples Repository.

Overview

This section explains how to integrate the Forms SDK into a custom HTML 5 Application. (Note: If you are using Camunda Tasklist you can skip this section. Camunda Tasklist readily integrates the Forms SDK.)

Getting a Distribution

Manual Download

The Forms SDK library can be downloaded from Github.

Bower

Alternatively, the Forms SDK can be installed using the Bower package manager:

bower install camunda-bpm-sdk-js --save

Dependency Management

The Forms SDK depends on the following libraries:

  • JQuery (or a compatible DOM manipulation Library).

The Forms SDK optionally depends on the following libraries:

  • AngularJS (v1.2.16).

Including the Library

Next, you need to add the JavaScript Library to the page.

<script src="jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="camunda-bpm-sdk.min.js" type="text/javascript"></script>

Or, with AngularJS Support:

<script src="angular.min.js" type="text/javascript"></script>
<script src="camunda-bpm-sdk-angular.js" type="text/javascript"></script>

Bootstrapping

Creating a Client

The Forms SDK uses an instance of the CamSDK.Client to communicate with the process engine (over the REST API):

var camClient = new CamSDK.Client({
  mock: false,
  apiUri: 'http://localhost:8080/engine-rest'
});

Creating a Form

In order to create a form, you need to create an instance of CamSDK.Form:

new CamSDK.Form({
  // ...
});

Providing a Task Id

In case the form is a task form (i.e., the submission of the form should trigger the completing of a task), you need to provide a taskId:

new CamSDK.Form({
  client: camClient,

  // the task ID
  taskId: 'someTaskId',

  //...
});

Providing a Process Definition Id

In case the form is a start form (i.e., the submission of the form should trigger a new process instance to start), you need to provide a processDefinitionId:

new CamSDK.Form({
  client: camClient,

  // the process definition ID
  processDefinitionId: 'someProcessDefinitionId',

  //...
});

Loading a Form from a URL

The Forms SDK can automatically load forms from a URL. The URL from which the form should be loaded is referenced using the formElement property.

In that case you need to create a container element somewhere in the DOM:

<div id="formContainer">
</div>

And reference it in the containerElement property when creating the CamSDK.Form instance:

new CamSDK.Form({
  client: camClient,

  // URL to the form
  formUrl: '/url/to/form.html',

  // the task ID
  taskId: 'someTaskId',

  // the container to which the form should be appended. Can be a DOM element or a jQuery wrapper
  containerElement: $('#formContainer'),

  done: function(error, camFormInstance) {
    // ..
  }
});

Using a form existing in the DOM

It is also possible to initialize the Form SDK for a form already existing in the DOM.

Assuming that you have an HTML <form ...> element present in the DOM:

<form id="myForm">
  <input ....>
</form>

You can create an instance of CamSDK.Form and attach it to the existing form like this:

new CamSDK.Form({
  client: camClient,

  // the task ID
  taskId: 'someTaskId',

  // the form element. Can be a DOM element or a jQuery wrapper
  formElement: $('#myForm'),

  done: function(error, camFormInstance) {
    // ..
  }
});

AngularJS Integration

Including the Angular Distribution

Make sure you include the AngularJS build of the Forms SDK:

<script src="angular.min.js" type="text/javascript"></script>
<script src="camunda-bpm-sdk-angular.js" type="text/javascript"></script>

Loading the Forms Module

Add the Forms SDK as module dependency to your application module:

angular.bootstrap(window.document, ['cam.embedded.forms', ...]);

Angular Directives & Compilation

If the form is loaded from a URL, the SDK makes sure that it is properly compiled and linked to the current Angular scope. This allows using Angular directives in forms loaded dynamically at runtime.

<form role="form" name="form">

<input type="text"
       cam-variable-name="CUSTOMER_ID"
       cam-variable-type="String"
       ng-model="customerId">

<p ng-show="customerId">Your input: <em>{{customerId}}</em></p>

</form>

Full Example

Full examples of how to integrate the Forms SDK in a custom application can be found in the Camunda BPM Examples Repository in Github.