Skip to content

Custom Model

This example demonstrates how to create a custom model implementation that persists data directly to localStorage, providing automatic persistence without keeping local copies in memory.

The NgDiagramComponent accepts any object that implements the ModelAdapter interface, which means you can create your own custom model implementations beyond the default SignalModelAdapter provided by initializeModel. This allows for advanced use cases like connecting to external data sources, implementing custom persistence layers, or integrating with existing state management solutions.

  • Direct localStorage Persistence: All data is read from and written directly to localStorage
  • Single Source of Truth: No local copies of data are maintained in memory
  • Automatic Synchronization: Changes are immediately persisted
  • Error Handling: Robust error handling for storage operations

The ModelAdapter interface defines the contract that any model implementation must fulfill. You can find the complete interface documentation in the API reference. The key methods include:

  • Data access: getNodes, getEdges, getMetadata
  • Data modification: updateNodes, updateEdges, updateMetadata
  • Change notification: onChange, unregisterOnChange
  • Lifecycle management: destroy, undo, redo, toJSON

This example demonstrates a custom model adapter that persists diagram data to localStorage. The data will survive page refreshes and browser sessions. You can try it by adding nodes and edges, then refreshing the page to see that your changes are retained.

import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import type { Node } from 'ng-diagram';
import { NgDiagramComponent, NgDiagramModelService } from 'ng-diagram';
import { LocalStorageModelAdapter } from './local-storage-model-adapter';
@Component({
selector: 'app-custom-model-example',
standalone: true,
imports: [CommonModule, NgDiagramComponent],
templateUrl: './custom-model-example.component.html',
styleUrl: './custom-model-example.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomModelExampleComponent {
private modelService = inject(NgDiagramModelService);
modelAdapter: LocalStorageModelAdapter = new LocalStorageModelAdapter(
'ng-diagram-custom-demo',
{
nodes: [
{
id: '1',
position: { x: 100, y: 100 },
data: { label: 'Custom Node 1' },
},
{
id: '2',
position: { x: 300, y: 100 },
data: { label: 'Custom Node 2' },
},
],
edges: [
{
id: 'edge-1',
source: '1',
target: '2',
sourcePort: 'port-right',
targetPort: 'port-left',
data: {},
},
],
metadata: { viewport: { x: 0, y: 0, scale: 1 } },
}
);
addNode() {
const existingNodes = this.modelService.nodes();
const newId = `node-${crypto.randomUUID()}`;
const randomX = Math.floor(Math.random() * 400) + 50;
const randomY = Math.floor(Math.random() * 300) + 50;
const newNode: Node = {
id: newId,
position: { x: randomX, y: randomY },
data: { label: `Custom Node ${existingNodes.length + 1}` },
};
this.modelService.addNodes([newNode]);
}
clearAll() {
const nodeIds = this.modelService.nodes().map((node) => node.id);
const edgeIds = this.modelService.edges().map((edge) => edge.id);
this.modelService.deleteNodes(nodeIds);
this.modelService.deleteEdges(edgeIds);
}
}