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]);});
Benefits
Section titled “Benefits”Performance
Section titled “Performance”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.
Consistency
Section titled “Consistency”All operations within a transaction succeed together, preventing partial state updates that could leave your diagram in an inconsistent state.
When to Use Transactions
Section titled “When to Use Transactions”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
Best Practices
Section titled “Best Practices”Group related operations together, but avoid making transactions too large or complex:
// ✅ Good - related operations grouped togetherthis.ngDiagramService.transaction(() => { this.ngDiagramModelService.addNodes([node1, node2, node3]); this.ngDiagramModelService.addEdges([edge1, edge2]);});
// ❌ Avoid - unrelated operations in same transactionthis.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 transactionthis.ngDiagramService.transaction(() => { for (const node of nodes) { this.ngDiagramModelService.updateNodeData(node); }});
// ❌ Avoid - transactions inside a loopfor (const node of nodes) { this.ngDiagramService.transaction(() => { this.ngDiagramModelService.updateNodeData(node); // Each iteration creates a separate transaction });}
Example
Section titled “Example”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.