BPMN Activities in Angular Diagram Component
26 Aug 202524 minutes to read
Overview
BPMN (Business Process Model and Notation) activities represent work performed within a business process. An activity
appears as a rounded rectangle and serves as the fundamental unit of work in process modeling.
Activities fall into two main categories:
- Task: A single unit of work that cannot be broken down into smaller components within the process model
- Subprocess: A compound activity that contains other activities and can be expanded to show additional detail
To create a BPMN activity, set the shape property to Activity. Specify the activity type using the shape.activity
property of the node. The default activity type is Task.
import { DiagramModule, BpmnDiagramsService ,DiagramComponent, NodeModel, BpmnShapeModel} from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150 [shape]='shape'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task'
},
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Tasks
The task
property of bpmn activity
defines specific task types such as user tasks, service tasks, or message tasks. The default task type is None. Different task types indicate the nature of work being performed and who or what performs it.
import { DiagramModule, BpmnDiagramsService,DiagramComponent, NodeModel, BpmnShapeModel } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150 [shape]='shape1'></e-node>
<e-node id='node2' [offsetX]=350 [offsetY]=150 [shape]='shape2'></e-node>
<e-node id='node3' [offsetX]=550 [offsetY]=150 [shape]='shape3'></e-node>
<e-node id='node4' [offsetX]=750 [offsetY]=150 [shape]='shape4'></e-node>
<e-node id='node5' [offsetX]=150 [offsetY]=350 [shape]='shape5'></e-node>
<e-node id='node6' [offsetX]=350 [offsetY]=350 [shape]='shape6'></e-node>
<e-node id='node7' [offsetX]=550 [offsetY]=350 [shape]='shape7'></e-node>
<e-node id='node8' [offsetX]=750 [offsetY]=350 [shape]='shape8'></e-node>
<e-node id='node9' [offsetX]=450 [offsetY]=550 [shape]='shape9'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape1: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the type of the task as Send
task: {
type: 'Send',
},
},
}
public shape2: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the type of the task as Send
task: {
type: 'Service'
}
},
}
public shape3: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the type of the task as Send
task: {
type: 'BusinessRule'
}
},
}
public shape4: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the type of the task as Send
task: {
type: 'Receive'
}
},
}
public shape5: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the type of the task as Send
task: {
type: 'InstantiatingReceive'
}
},
}
public shape6: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the type of the task as Send
task: {
type: 'Manual'
}
},
}
public shape7: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the type of the task as Send
task: {
type: 'Script'
}
},
}
public shape8: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the type of the task as Send
task: {
type: 'User'
}
},
}
public shape9: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the type of the task as Send
task: {
type: 'None'
}
},
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
The following table shows the available BPMN task types:
Shape | Image |
---|---|
Service | ![]() |
Send | ![]() |
Receive | ![]() |
Instantiating Receive | ![]() |
Manual | ![]() |
Business Rule | ![]() |
User | ![]() |
Script | ![]() |
Subprocesses
Subprocesses represent activities that contain other processes or activities within them. They provide a way to organize complex processes hierarchically and can be expanded or collapsed to show or hide internal details.
Collapsed Subprocess
A collapsed subprocess
appears as a single activity but contains additional process details that remain hidden. This approach helps maintain process diagram clarity while preserving detailed information.
import { DiagramModule, BpmnDiagramsService, DiagramComponent, NodeModel, BpmnShapeModel } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150 [shape]='shape'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'SubProcess',
subProcess: {
collapsed: true
}
},
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Loop Characteristics
Loop
characteristics indicate that an activity repeats until a specified condition is met. The loop property of bpmn activity defines the repetition behavior. The default value is none.
import { DiagramModule, BpmnDiagramsService, DiagramComponent, NodeModel, BpmnShapeModel} from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=100 [offsetY]=100 [shape]='shape1'></e-node>
<e-node id='node2' [offsetX]=300 [offsetY]=100 [shape]='shape2'></e-node>
<e-node id='node3' [offsetX]=500 [offsetY]=100 [shape]='shape3'></e-node>
<e-node id='node4' [offsetX]=700 [offsetY]=100 [shape]='shape4'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape1: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets loop of the task as Standard
task: {
loop: 'Standard'
}
},
}
public shape2: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'SubProcess',
//Sets collapsed as true and loop as None
subProcess: {
collapsed: true,
loop: 'None',
},
},
}
public shape3: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'SubProcess',
//Sets collapsed as true and loop as ParallelMultiInstance
subProcess: {
collapsed: true,
loop: 'ParallelMultiInstance',
},
},
}
public shape4: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'SubProcess',
//Sets collapsed as true and loop as SequenceMultiInstance
subProcess: {
collapsed: true,
loop: 'SequenceMultiInstance',
},
},
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
The following table shows the available loop types for both tasks and subprocesses:
Loops | Task | Subprocess |
---|---|---|
Standard | ![]() |
![]() |
SequenceMultiInstance | ![]() |
![]() |
ParallelMultiInstance | ![]() |
![]() |
Compensation
Compensation
indicates that an activity can undo or compensate for work performed by another activity. This becomes relevant when a process fails after partial completion and requires cleanup activities. Enable compensation using the compensation property of the bpmn activity. The default value is false.
import { DiagramModule, BpmnDiagramsService ,DiagramComponent, NodeModel, BpmnShapeModel } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150 [shape]='shape'></e-node>
<e-node id='node2' [offsetX]=300 [offsetY]=150 [shape]='shape1'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets compensation of the task as true
task: {
compensation: true
}
},
}
public shape1: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as SubProcess
activity: {
activity: 'SubProcess',
//Set the collapsed as true and compensation as true
subProcess: {
collapsed: true,
compensation: true
}
},
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Call Activity
A call
activity references a global process or subprocess that exists outside the current process definition. This promotes reusable across multiple processes. Enable call activity behavior using the call property of the task. The default value is false.
import { DiagramModule, BpmnDiagramsService,DiagramComponent, NodeModel, BpmnShapeModel } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150 [shape]='shape'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'Task',
//Sets the call of the task as true
task: {
call: true
}
},
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
NOTE
The call property applies only to task-type activities.
Ad hoc
An adhoc
subprocess contains activities that performers can execute in any order or skip entirely, provided the overall objective is achieved. Enable ad hoc behavior using the adhoc property of the subprocess. The default value is false.
import { DiagramModule, BpmnDiagramsService,DiagramComponent, NodeModel, BpmnShapeModel } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150 [shape]='shape'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'SubProcess',
//Sets collapsed as true and adhoc as true
subProcess: {
collapsed: true,
adhoc: true
}
},
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Boundary Types
The boundary
property defines the visual boundary style of a subprocess, indicating different subprocess characteristics. The default value is default.
import { DiagramModule, BpmnDiagramsService, DiagramComponent, NodeModel, BpmnShapeModel } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=250 [offsetY]=250 [shape]='shape'></e-node>
<e-node id='node2' [offsetX]=450 [offsetY]=250 [shape]='shape1'></e-node>
<e-node id='node3' [offsetX]=650 [offsetY]=250 [shape]='shape2'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'SubProcess',
//Sets collapsed as true and boundary as Call
subProcess: {
collapsed: true,
boundary: 'Call'
}
},
}
public shape1: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'SubProcess',
//Sets collapsed as true and boundary as Event
subProcess: {
collapsed: true,
boundary: 'Event'
}
},
}
public shape2: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as Task
activity: {
activity: 'SubProcess',
//Sets collapsed as true and boundary as Default
subProcess: {
collapsed: false,
boundary: 'Default'
}
},
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
The following table shows the available boundary types:
Boundary | Image |
---|---|
Call | ![]() |
Event | ![]() |
Default | ![]() |
Specialized Subprocess Types
BPMN defines two specialized subprocess types for specific business scenarios:
Event Subprocess
An event subprocess executes when triggered by a specific event rather than following the normal process flow. Event subprocesses reside within other subprocesses but remain outside the main sequence flow until activated.
Configure an event subprocess using the event
and trigger
properties. The type
property determines whether the subprocess is an event subprocess or transaction subprocess.
import { DiagramModule, BpmnDiagramsService , DiagramComponent, NodeModel, BpmnShapeModel } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150 [shape]='shape'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape: BpmnShapeModel = {
type: 'Bpmn',
shape: 'Activity',
//Sets activity as SubProcess
activity: {
activity: 'SubProcess',
//Sets the collapsed as false and type as Event
subProcess: {
collapsed: false,
type: 'Event',
//Sets event as Start and trigger as Message
events: [
{
id: 'event',
event: 'Start',
trigger: 'Message',
offset: { x: 0.5, y: 0 },
},
],
}
}
} as BpmnShapeModel;
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Transaction Subprocess
A transaction
subprocess represents a group of activities that must all complete successfully or the entire transaction is undone. Transaction results include Successful Completion, Unsuccessful Completion (Cancel), or Hazard (Exception).
The event
property allows representation of these results as events attached to the subprocess. Configure event properties as follows:
- Event type: Defines the triggering event type for the subprocess
- Event name: Identifies the event during runtime
- Offset: Sets the event shape position relative to the parent (as a fraction/ratio)
- Trigger: Specifies the event trigger type
- Ports and labels: Define additional interaction points and descriptive text
import { DiagramModule, BpmnDiagramsService,DiagramComponent, NodeModel, BpmnShapeModel } from '@syncfusion/ej2-angular-diagrams'
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
@Component({
imports: [
DiagramModule
],
providers: [BpmnDiagramsService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [getNodeDefaults] ='getNodeDefaults'>
<e-nodes>
<e-node id='node1' [offsetX]=150 [offsetY]=150 [shape]='shape'></e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public shape: BpmnShapeModel = {
//Sets type as Bpmn and shape as activity
type: 'Bpmn',
shape: 'Activity',
//Sets activity as SubProcess
activity: {
activity: 'SubProcess',
//Sets the collapsed as true and type as Event
subProcess: {
collapsed: true,
type: 'Transaction',
//Sets transaction
transaction: {
success: {
id: 'success',
event: 'Start',
trigger: 'None',
},
failure: {
id: 'failure',
event: 'ThrowingIntermediate',
trigger: 'Error',
},
cancel: {
id: 'cancel',
event: 'End',
trigger: 'Cancel',
},
},
},
},
}
public getNodeDefaults(node: NodeModel): NodeModel {
node.height = 100;
node.width = 100;
return node;
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));