Camunda嵌入式表单如何指定绑定变量作用域?任务本地变量需求
Great question—this is a common pain point with Camunda's embedded forms, since the default variable binding defaults to process instance scope. That’s why you’re seeing later user tasks with the same variable name auto-populating with old values, and your process instance variable list (in Cockpit under Running Process Instances > [Process Name] > [Instance GUID] > Variables) is getting cluttered with values that only matter during form submission.
You already know workarounds like resetting variables programmatically or using unique variable names, but using task-local variables is the cleaner, more intentional solution. The catch is Camunda doesn’t have a built-in attribute (like cam-variable-scope="local") to set this directly in your form markup. Here’s how to fix it:
Frontend Solution: Override Form Submission with AngularJS Hooks
Camunda’s embedded forms use AngularJS under the hood, so you can hook into the form submission lifecycle to save your value as a task-local variable instead of a process variable.
Step 1: Update Your Form Markup
Add an on-submit handler to your form, and use ng-model to bind the input value to a scope variable (instead of relying on the default cam-variable-name binding alone):
<form name="referenceForm" cam-form-submit="handleSubmit()"> <div class="form-group"> <label for="reference">Reference</label> <input class="form-control" id="reference" name="reference" ng-model="formValues.reference" type="text" /> </div> <button type="submit" class="btn btn-primary">Submit Task</button> </form>
(Note: You can remove the cam-variable-name and cam-variable-type attributes here since we’re handling the variable logic manually.)
Step 2: Add the Submission Handler Script
Include a <script> block with the handleSubmit() function to interact with Camunda’s task service:
<script cam-script type="text/form-script"> $scope.formValues = {}; // Initialize empty form object $scope.handleSubmit = function() { const taskId = camForm.taskId; const referenceValue = $scope.formValues.reference; // Save the value as a task-local variable camForm.taskService.setVariableLocal(taskId, 'reference', referenceValue) .then(() => { // Once the local variable is set, complete the task return camForm.taskService.complete(taskId); }) .catch(error => { console.error('Failed to set task-local variable:', error); alert('There was an error submitting your form. Please try again.'); }); // Prevent default form behavior (which would create a process variable) return false; }; </script>
Backend Solution: Use a Task Listener
If you prefer handling this logic on the backend (to keep frontend code minimal), you can add a task listener to your user task in the BPMN model. This listener will move the process variable to task-local scope when the task is completed.
Step 1: Add the Listener in Camunda Modeler
- Select your user task in the BPMN diagram.
- Go to the Listeners tab.
- Add a new listener with:
- Event Type:
complete - Implementation Type:
Class(orDelegate Expressionif you use Spring) - Class/Expression: Point to a custom Java delegate class
- Event Type:
Step 2: Implement the Delegate Class
Here’s a simple Java delegate that moves the reference variable to task-local scope and cleans up the process variable:
import org.camunda.bpm.engine.delegate.DelegateTask; import org.camunda.bpm.engine.delegate.TaskListener; public class MoveToLocalVariableListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { // Get the value from the process variable Object referenceValue = delegateTask.getVariable("reference"); if (referenceValue != null) { // Set it as a task-local variable delegateTask.setVariableLocal("reference", referenceValue); // Remove the process variable to avoid clutter delegateTask.removeVariable("reference"); } } }
Key Benefits of Task-Local Variables
- No cross-task contamination: Later forms using the same variable name won’t auto-populate with old values.
- Cleaner process variables: Only variables that need to persist across tasks stay in the process instance scope.
- Intentional scope control: You’re explicitly defining where the variable lives, which makes your process easier to debug and maintain.
内容的提问来源于stack exchange,提问作者Kevin Swann

