Skip to content

Transactions

Transactions in ngDiagram provide a mechanism for batching multiple state changes into atomic operation. This is particularly useful for complex operations that involve multiple nodes and edges, ensuring better performance.

The transaction API is straightforward - simply wrap your operations in a callback.

this.ngDiagramService.transaction(() => {
this.ngDiagramModelService.addNodes([node1, node2]);
this.ngDiagramModelService.addEdges([edge1]);
});

Transactions batch multiple operations together, reducing the number of state updates and re-renders. Instead of triggering change detection for each individual operation, all changes are applied at once.

All operations within a transaction succeed together, preventing partial state updates that could leave your diagram in an inconsistent state.

Use transactions for:

  • Complex multi-step operations - Creating multiple related nodes and edges
  • Bulk operations - Adding or updating many elements at once
  • Performance optimization - Reducing the number of state updates

Group related operations together, but avoid making transactions too large or complex:

// ✅ Good - related operations grouped together
this.ngDiagramService.transaction(() => {
this.ngDiagramModelService.addNodes([node1, node2, node3]);
this.ngDiagramModelService.addEdges([edge1, edge2]);
});
// ❌ Avoid - unrelated operations in same transaction
this.ngDiagramService.transaction(() => {
this.ngDiagramModelService.addNodes([...]);
this.updateUserPreferences(); // Unrelated operation
this.updateDiagramName(); // Another unrelated operation
});

Wrap the entire loop in a single transaction instead of starting one for every iteration to minimize overhead

// ✅ Good - loop inside transaction
this.ngDiagramService.transaction(() => {
for (const node of nodes) {
this.ngDiagramModelService.updateNodeData(node);
}
});
// ❌ Avoid - transactions inside a loop
for (const node of nodes) {
this.ngDiagramService.transaction(() => {
this.ngDiagramModelService.updateNodeData(node); // Each iteration creates a separate transaction
});
}
import '@angular/compiler';
import { Component, inject } from '@angular/core';
import {
initializeModel,
NgDiagramComponent,
NgDiagramModelService,
NgDiagramService,
provideNgDiagram,
type NgDiagramConfig,
} from 'ng-diagram';
@Component({
imports: [NgDiagramComponent],
providers: [provideNgDiagram()],
template: `
<div class="diagram-container">
<ng-diagram [model]="model" [config]="config" />
<div class="toolbar">
<button (click)="onTestTransactionClick()">
Create diagram (Transaction)
</button>
<button (click)="onTestWithoutTransactionClick()">
Create diagram (Without Transaction)
</button>
</div>
</div>
`,
styles: `
:host {
flex: 1;
display: flex;
height: 100%;
position: relative;
}
.diagram-container {
display: flex;
width: 100%;
height: 30rem;
border: 5px solid var(--ngd-ui-border-default);
background-color: var(--ngd-ui-bg-tertiary-default);
}
.toolbar {
position: absolute;
display: flex;
gap: 0.5rem;
padding: 0.5rem;
justify-content: center;
width: 100%;
}
`,
})
export class NgDiagramComponentContainer {
private ngDiagramService = inject(NgDiagramService);
private modelService = inject(NgDiagramModelService);
config: NgDiagramConfig = {
debugMode: true,
};
model = initializeModel({
metadata: { viewport: { x: 130, y: 25, scale: 1 } },
nodes: [
{
id: '1',
position: { x: 100, y: 200 },
data: { label: 'Use Buttons to test transaction' },
},
],
});
onTestTransactionClick() {
this.cleanDiagram();
this.ngDiagramService.transaction(() => {
this.createDiagram('Transaction Node');
});
}
onTestWithoutTransactionClick() {
this.cleanDiagram();
this.createDiagram('Non-transaction Node');
}
private createDiagram(nodeName: string) {
// Transaction example: All operations are batched together
this.modelService.addNodes([
{
id: '1',
position: { x: 100, y: 100 },
data: { label: nodeName },
},
{
id: '2',
position: { x: 100, y: 200 },
data: { label: nodeName },
},
{
id: '3',
position: { x: 100, y: 300 },
data: { label: nodeName },
},
]);
// Update node data within the same transaction
this.modelService.updateNodeData('1', {
label: `Updated ${nodeName} 1`,
});
this.modelService.updateNodeData('2', {
label: `Updated ${nodeName} 2`,
});
this.modelService.updateNodeData('3', {
label: `Updated ${nodeName} 3`,
});
}
private cleanDiagram() {
this.modelService.deleteNodes(
this.modelService.nodes().map((node) => node.id)
);
}
}

Whether you’re building simple diagrams or complex applications, transactions help ensure data consistency and optimal performance.