synergycodes/ng-diagram/ng-diagram-state-updates
Claude Code and agent skill by synergycodes/ng-diagram
- community
Checking that the SKILL.md file is still in the repository.
Use when ng-diagram code adds, updates, deletes or reads nodes and edges (NgDiagramModelService) - typed data, updateNodeData dropping fields, nodes() stale after await, waitForMeasurements, model queries (getConnectedEdges, getOverlappingNodes).
Install
npx vskill@latest install synergycodes/ng-diagram/ng-diagram-state-updatesSKILL.md
State updates and reads (NgDiagramModelService)
How to change and read diagram data from code: create/update/delete, typed data, awaiting changes, waitForMeasurements, and the query methods. Batching and operation order are in ng-diagram-transactions, save/load and custom stores in ng-diagram-persistence, validating or blocking changes in ng-diagram-middleware.
Rules
- Change state only through the services (
NgDiagramModelService,NgDiagramSelectionService,NgDiagramGroupsService,NgDiagramNodeService, ...). Do not mutate objects fromnodes()orgetNodeById(), and do not call update methods on the model adapter. Changes made through the services run the middleware chain (edge routing, z-index, events); a direct mutation skips it and is not even detected as a change. - Every mutating method returns `Promise<void>` (since 1.3.0; before it returned
void). It resolves once the change is in the model.awaitit when the next line depends on the change; otherwise writevoid this.modelService.addNodes(...)or ignore the promise. - Read fresh state with getters, not signals. After
await,getNodeById,getEdgeById,getConnectedEdges,getChildrenandgetModel().getNodes()already return the new state. Thenodes(),edges(),metadata()signals (andNgDiagramSelectionService.selection()) refresh with Angular change detection, so right after anawaitand inside diagram event handlers they can still show the old state. Use the signals in templates,computed()andeffect(). - `updateNodeData` / `updateEdgeData` replace `data` completely. Spread the current data to keep the other fields.
updateNode/updateEdgemerge top-level properties, but a nested value (position,size,data) is replaced as a whole. - Pass new objects. A value with the same reference as the current one is not a change, so mutating
node.dataand passing the same object back does nothing. - Batch.
addNodes,updateNodes,updateEdges,deleteNodesanddeleteEdgestake arrays. Each call is one pass through the whole middleware chain; for mixed operations use one transaction (ng-diagram-transactions). - Never write system-owned properties (
measuredPorts,measuredBounds,measuredLabels,computedZIndex,computedHidden,sourcePosition/targetPositionof connected edge ends). Seereferences/model-reference.mdinng-diagram-fundamentals. - Wait for the engine. Before
<ng-diagram>has created its engine, service calls throw[ngDiagram] Library engine not initialized yet.Run startup code from(diagramInit)or whenNgDiagramService.isInitialized()is true (ng-diagram-model-init).
Typed data and partial updates
Define the data type once and pass it as the generic (getter generics since 1.2.0). With the generic, the compiler reports a missing required field; without it, a forgotten field is dropped silently at runtime.
Inject the services in the component that declares provideNgDiagram() or in a component inside it (see ng-diagram-setup). For a properties panel bound to the selection, see ng-diagram-selection-clipboard.
Add a node where the user clicked, then select it
Keep the two awaits separate: select() builds its change from the committed model, so inside one transaction it cannot see a node added in the same transaction.
Wait for measurements, bulk changes, queries
{ waitForMeasurements: true } (since 1.3.0) waits only for the elements that this call changes. It exists where a change can trigger measurement: addNodes, addEdges, updateNode, updateNodes, updateNodeData, updateEdge, updateEdges, updateEdgeData, NgDiagramNodeService.resizeNode and NgDiagramClipboardService.paste. To add nodes and edges and then fit, put both calls in one transaction with { waitForMeasurements: true } (ng-diagram-transactions). Deletes, grouping, rotation, selection and viewport calls have nothing new to measure: awaiting them is enough.
Query methods
Points and ranges are flow (diagram) coordinates; convert pointer positions with NgDiagramViewportService.clientToFlowPosition(). All getters that return nodes or edges take an optional data-type generic.
| Method | Returns | |
|---|---|---|
getNodeById(id), getEdgeById(id) | the element or null | |
getConnectedEdges(nodeId) | edges that have the node as source or target | |
getConnectedNodes(nodeId) | nodes at the other end of those edges (free edge ends are skipped) | |
getNodeEnds(edgeId) | { source, target } nodes, or null when the edge or either end node is missing (always null for a dangling edge) | |
getChildren(groupId) / getChildrenNested(groupId) | direct children / all descendants | |
isNestedChild(nodeId, groupId) | true when the node is a descendant at any depth | |
getParentHierarchy(nodeId) | parent groups, closest first | |
getNodesInRange(point, range) | nodes whose rectangle touches the square point ± range | |
getNearestNodeInRange(point, range) | the closest of those, or null | |
getNearestPortInRange(point, range) | a Port (it has nodeId) or null; ports hidden in the template are skipped | |
getOverlappingNodes(nodeIdOrNode) | nodes whose rectangle (rotation included) intersects the node; pass a Node object to test geometry that is not committed yet, for example in a middleware | |
computePartsBounds(nodes, edges) | Rect around the nodes' measuredBounds (ports and rotation included) and the edges' points and labels | |
getDanglingEndpoints(), getNearestDanglingEndpointInRange() | free edge ends (since 1.4.0), see ng-diagram-dangling-edges |
Edge cases
- Deleting nodes also deletes their connected edges, and deleting a group deletes all its descendants (since 1.4.0; before, children stayed with a
groupIdthat pointed at a deleted node). To keep the children,awaitNgDiagramGroupsService.removeFromGroup(groupId, childIds)first and then calldeleteNodes, as two awaited steps and not in one transaction:deleteNodescollects the descendants from the committed model when it is called. WithdanglingEdges.enabledanddanglingEdges.detachOnNodeDelete, connected edges are kept as dangling edges (ng-diagram-dangling-edges). - Inside a transaction the returned promise resolves at once and the change is applied when the transaction commits. Calls that look things up (
select,deleteNodes, grouping,attachEdge) see the model as it was before the transaction. - The `nodes()`, `edges()` and `metadata()` signals are filled only after `diagramInit`: before that (and still inside the
diagramInithandler) they hold empty arrays and a default viewport; use the getters there. After a new model is assigned, they keep the previous model's data until itsdiagramInit. - No service method changes `metadata.data` (diagram-level data such as a title). Set it with
initializeModel({ metadata: { data } })or keep it in your own state (references/model-reference.mdinng-diagram-fundamentals). - `addNodes` / `addEdges` do not check ids. An element with an id that already exists replaces that element. Generate unique ids.
- Updates for unknown ids are ignored without an error.
- Spatial queries (
getNodesInRange,getNearestNodeInRange,getNearestPortInRange,getOverlappingNodes) skip effectively hidden nodes and nodes without asize(not measured yet). Their index is refreshed when the model notifies a change, which the default model does with change detection, so right after anawaitthey can miss nodes that were just added or moved. - `computePartsBounds` needs measured nodes. When nothing is measured it returns
{ x: 0, y: 0, width: 0, height: 0 }. Since 1.4.0 hidden elements are left out, and an emptyedgesarray no longer pulls the result to the origin. - Errors and cancels. When a middleware throws, the returned promise rejects and the change is dropped (since 1.3.0; before, the diagram stopped applying updates). When a middleware calls
cancel(), the promise resolves normally and nothing is applied. - `waitForMeasurements` inside a transaction is ignored with the console warning
[ngDiagram] waitForMeasurements is ignored inside a transaction — pass { waitForMeasurements: true } to the transaction itself instead.The promise settles on its own: elements that produce no new measurement (hidden ones since 1.4.0, or unchanged ones) do not block it. - `detachEdge` does nothing (and logs a warning) unless
danglingEdges.enabledis set; `attachEdge` resolves tofalsewhen the connection is not valid.
Symptom → fix
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/ng-diagram-state-updates/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/synergycodes/ng-diagram/ng-diagram-state-updates)