Properties Sidebar Example
This example demonstrates how to build an interactive properties panel that automatically updates when nodes are selected and allows real-time editing of node attributes in ngDiagram.
import '@angular/compiler';
import { Component } from '@angular/core';import { initializeModel, NgDiagramBackgroundComponent, NgDiagramComponent, provideNgDiagram, type NgDiagramConfig,} from 'ng-diagram';import { SidebarContainer } from './sidebar/sidebar.component';
@Component({ imports: [NgDiagramComponent, NgDiagramBackgroundComponent, SidebarContainer], providers: [provideNgDiagram()], template: ` <div class="not-content diagram"> <ng-diagram [model]="model" [config]="config"> <ng-diagram-background /> </ng-diagram> </div> <sidebar-container /> `, styleUrls: ['./diagram.component.scss'],})export class DiagramComponent { config = { zoom: { zoomToFit: { onInit: true, padding: [50, 315, 50, 50], }, }, } satisfies NgDiagramConfig;
model = initializeModel({ nodes: [ { id: '1', position: { x: 50, y: 120 }, data: { label: 'Node 1' }, rotatable: true, }, { id: '2', position: { x: 300, y: 120 }, data: { label: 'Node 2' } }, ], edges: [ { id: '1', source: '1', sourcePort: 'port-right', targetPort: 'port-left', target: '2', data: {}, }, ], });}import '@angular/compiler';import { Component, computed, inject } from '@angular/core';import { NgDiagramModelService, NgDiagramSelectionService } from 'ng-diagram';
type Data = { label: string;};
@Component({ selector: 'sidebar-container', templateUrl: `./sidebar.component.html`, styleUrl: './sidebar.component.scss',})export class SidebarContainer { private readonly modelService = inject(NgDiagramModelService); private readonly selectionService = inject(NgDiagramSelectionService); private readonly selectedNode = computed( () => this.selectionService.selection().nodes[0] ?? null );
id = computed(() => this.selectedNode()?.id ?? null); label = computed(() => { const data = this.selectedNode()?.data as Data | undefined; return data?.label ?? ''; }); isRotatable = computed(() => this.selectedNode()?.rotatable ?? false); isResizable = computed(() => this.selectedNode()?.resizable ?? false); isEnabled = computed(() => !!this.selectedNode());
onInput(event: Event) { if (!this.selectedNode()) return; const value = (event.target as HTMLInputElement).value; this.modelService.updateNodeData<{ label: string }>(this.id()!, { label: value, }); }
onIsResizableChange(value: boolean) { if (!this.selectedNode()) return; this.modelService.updateNode(this.id()!, { resizable: value }); }
onIsRotatableChange(value: boolean) { if (!this.selectedNode()) return; this.modelService.updateNode(this.id()!, { rotatable: value }); }}<div class="sidebar"> <div class="vertical"> <span>Selected node</span> <input [value]="label()" [disabled]="!isEnabled()" (input)="onInput($event)" /> </div> <div class="horizontal"> <input #isResizableCheckbox type="checkbox" id="isResizable" name="isResizable" [checked]="isResizable()" [disabled]="!isEnabled()" (change)="onIsResizableChange(isResizableCheckbox.checked)" /> <label for="isResizable">Is Resizable</label> </div> <div class="horizontal"> <input #isRotatableCheckbox type="checkbox" id="isRotatable" name="isRotatable" [checked]="isRotatable()" [disabled]="!isEnabled()" (change)="onIsRotatableChange(isRotatableCheckbox.checked)" /> <label for="isRotatable">Is Rotatable</label> </div></div>:host { position: relative; display: flex;}
.diagram { display: flex; width: 100%; height: var(--ng-diagram-height); border: var(--ng-diagram-border);}:host { position: absolute; top: 0; right: 0; height: 90%; padding: 1rem; margin-top: 0;
.sidebar { display: flex; flex-direction: column; background-color: var(--ngd-node-bg-primary-default); border: var(--ngd-node-border-size) solid var(--ngd-node-border-color); padding: 1rem; gap: 0.5rem; height: 100%; width: 200px; user-select: none;
.horizontal { display: flex; gap: 0.5rem; }
.vertical { display: flex; gap: 0.25rem; flex-direction: column; } }}Additional Explanation
Section titled “Additional Explanation”Key Concepts
Section titled “Key Concepts”- Selection Tracking: Uses
NgDiagramSelectionService.selection()to track selected nodes. - Computed Properties: Angular computed signals automatically update the UI when node properties change.
- Simple Update Methods: Direct calls to
updateNodeData()andupdateNode()for property modifications.
How It Works
Section titled “How It Works”The sidebar component automatically:
- Observes the current selection using the model service.
- Displays the selected node’s properties (label, resizable, rotatable).
- Updates the node in real-time when properties are changed.
- Disables controls when no node is selected.
This pattern makes it easy to create property editors for any node attributes you need to expose to users.