UNPKG

28.7 kBHTMLView Raw
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4<meta charset="utf-8"/>
5<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
6
7<link rel="stylesheet" href="../assets/css/style.css"/>
8<!-- Copyright 1998-2021 by Northwoods Software Corporation. --> <title> GoJS Transactions -- Northwoods Software </title>
9 <link rel="stylesheet" href="../assets/css/prism.css" />
10 </head>
11 <script>
12
13 window.diagrams = [];
14 window.goCode = function(pre, w, h, parentid, animation) {
15 window.diagrams.push([pre, w, h, parentid, animation]);
16 }
17 </script>
18 <body>
19 <nav id="navTop" class="w-full z-30 top-0 text-white bg-nwoods-primary">
20 <div class="w-full container max-w-screen-lg mx-auto flex flex-wrap sm:flex-nowrap items-center justify-between mt-0 py-2">
21 <div class="md:pl-4">
22 <a class="text-white hover:text-white no-underline hover:no-underline
23 font-bold text-2xl lg:text-4xl rounded-lg hover:bg-nwoods-secondary " href="../">
24 <h1 class="mb-0 p-1 ">GoJS</h1>
25 </a>
26 </div>
27 <button id="topnavButton" class="rounded-lg sm:hidden focus:outline-none focus:ring" aria-label="Navigation">
28 <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
29 <path id="topnavOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
30 <path id="topnavClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
31 </svg>
32 </button>
33 <div id="topnavList" class="hidden sm:block items-center w-auto mt-0 text-white p-0 z-20">
34 <ul class="list-reset list-none font-semibold flex justify-end flex-wrap sm:flex-nowrap items-center px-0 pb-0">
35 <li class="p-1 sm:p-0"><a class="topnav-link" href="../learn/">Learn</a></li>
36 <li class="p-1 sm:p-0"><a class="topnav-link" href="../samples/">Samples</a></li>
37 <li class="p-1 sm:p-0"><a class="topnav-link" href="../intro/">Intro</a></li>
38 <li class="p-1 sm:p-0"><a class="topnav-link" href="../api/">API</a></li>
39 <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/products/register.html">Register</a></li>
40 <li class="p-1 sm:p-0"><a class="topnav-link" href="../download.html">Download</a></li>
41 <li class="p-1 sm:p-0"><a class="topnav-link" href="https://forum.nwoods.com/c/gojs/11">Forum</a></li>
42 <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/contact.html"
43 target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a></li>
44 <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/sales/index.html"
45 target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a></li>
46 </ul>
47 </div>
48 </div>
49 <hr class="border-b border-gray-600 opacity-50 my-0 py-0" />
50 </nav>
51
52 <div class="md:flex flex-col md:flex-row md:min-h-screen w-full max-w-screen-xl mx-auto">
53
54 <div id="navSide" class="flex flex-col w-full md:w-40 lg:w-48 text-gray-700 bg-white flex-shrink-0">
55 <div class="flex-shrink-0 px-8 py-4">
56 <button id="navButton" class="rounded-lg md:hidden focus:outline-none focus:ring" aria-label="Navigation">
57 <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
58 <path id="navOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
59 <path id="navClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
60 </svg>
61 </button>
62 </div>
63 <nav id="navList" class="min-h-screen hidden md:block sidebar-nav flex-grow px-1 lg:px-4 pb-4 md:pb-0 md:overflow-y-auto break-words">
64 <a href="index.html">Basics</a>
65 <a href="buildingObjects.html">Building Parts</a>
66 <a href="usingModels.html">Using Models</a>
67 <a href="dataBinding.html">Data Binding</a>
68 <a href="react.html">GoJS with React</a>
69 <a href="angular.html">GoJS with Angular</a>
70 <a href="textBlocks.html">TextBlocks</a>
71 <a href="shapes.html">Shapes</a>
72 <a href="pictures.html">Pictures</a>
73 <a href="panels.html">Panels</a>
74 <a href="tablePanels.html">Table Panels</a>
75 <a href="brush.html">Brushes</a>
76 <a href="sizing.html">Sizing Objects</a>
77 <a href="itemArrays.html">Item Arrays</a>
78 <a href="changedEvents.html">Changed Events</a>
79 <a href="transactions.html">Transactions</a>
80 <a href="viewport.html">Coordinates</a>
81 <a href="initialView.html">Initial View</a>
82 <a href="collections.html">Collections</a>
83 <a href="links.html">Links</a>
84 <a href="linkLabels.html">Link Labels</a>
85 <a href="connectionPoints.html">Link Points</a>
86 <a href="ports.html">Ports</a>
87 <a href="nodes.html">Nodes</a>
88 <a href="debugging.html">Debugging</a>
89 <a href="layouts.html">Layouts</a>
90 <a href="trees.html">Trees</a>
91 <a href="subtrees.html">SubTrees</a>
92 <a href="groups.html">Groups</a>
93 <a href="subgraphs.html">SubGraphs</a>
94 <a href="sizedGroups.html">Sized Groups</a>
95 <a href="selection.html">Selection</a>
96 <a href="highlighting.html">Highlighting</a>
97 <a href="animation.html">Animation</a>
98 <a href="toolTips.html">ToolTips</a>
99 <a href="contextmenus.html">Context Menus</a>
100 <a href="events.html">Diagram Events</a>
101 <a href="tools.html">Tools</a>
102 <a href="commands.html">Commands</a>
103 <a href="permissions.html">Permissions</a>
104 <a href="validation.html">Validation</a>
105 <a href="HTMLInteraction.html">HTML Interaction</a>
106 <a href="layers.html">Layers &amp; Z-ordering</a>
107 <a href="palette.html">Palette</a>
108 <a href="overview.html">Overview</a>
109 <a href="resizing.html">Resizing Diagrams</a>
110 <a href="replacingDeleting.html">Replacing and Deleting</a>
111 <a href="buttons.html">Buttons</a>
112 <a href="templateMaps.html">Template Maps</a>
113 <a href="legends.html">Legends and Titles</a>
114 <a href="extensions.html">Extensions</a>
115 <a href="geometry.html">Geometry Strings</a>
116 <a href="grids.html">Grid Patterns</a>
117 <a href="graduatedPanels.html">Graduated Panels</a>
118 <a href="makingImages.html">Diagram Images</a>
119 <a href="makingSVG.html">Diagram SVG</a>
120 <a href="printing.html">Printing</a>
121 <a href="serverSideImages.html">Server-side Images</a>
122 <a href="nodeScript.html">GoJS in Node.js</a>
123 <a href="testing.html">Testing</a>
124 <a href="storage.html">Storage</a>
125 <a href="performance.html">Performance</a>
126 <a href="source.html">Building from Source</a>
127 <a href="platforms.html">Platforms</a>
128 <a href="deployment.html">Deployment</a>
129 </nav>
130 </div>
131 <div class="pt-4 px-2 md:px-0 lg:px-4 pb-16 w-full overflow-hidden">
132
133
134
135
136<h1>Transactions and the UndoManager</h1>
137<p>
138<b>GoJS</b> models and diagrams make use of an <a>UndoManager</a> that can record all changes and support
139undoing and redoing those changes.
140Each state change is recorded in a <a>ChangedEvent</a>, which includes enough information about both before and after
141to be able to reproduce the state change in either direction, backward (undo) or forward (redo).
142Such changes are grouped together into <a>Transaction</a>s so that a user action, which may result in many changes,
143can be undone and redone as a single operation.
144</p>
145<p>
146Not all state changes result in <a>ChangedEvent</a>s that can be recorded by the UndoManager.
147Some properties are considered transient, such as <a>Diagram.position</a>, <a>Diagram.scale</a>,
148<a>Diagram.currentTool</a>, <a>Diagram.currentCursor</a>, or <a>Diagram.isModified</a>.
149Some changes are structural or considered unchanging, such as <a>Diagram.model</a>, any property of <a>CommandHandler</a>,
150or any of the tool or layout properties.
151But most <a>GraphObject</a> and model properties do raise a ChangedEvent on the Diagram or Model, respectively,
152when a property value has been changed.
153</p>
154
155<h2 id="Transactions">Transactions</h2>
156<p>
157Whenever you modify a model or its data programmatically in response to some event, you should wrap the code in a transaction.
158Call <a>Diagram.startTransaction</a> or <a>Model.startTransaction</a>, make the changes,
159and then call <a>Diagram.commitTransaction</a> or <a>Model.commitTransaction</a>.
160Although the primary benefit from using transactions is to group together side-effects for undo/redo,
161you should use transactions even if your application does not support undo/redo by the user.
162</p>
163<p>
164As with database transactions, you will want to perform transactions that are short and infrequent.
165Do not leave transactions ongoing between user actions.
166Consider whether it would be better to have a single transaction surrounding a loop
167instead of starting and finishing a transaction repeatedly within a loop.
168Do not execute transactions within a property setter -- such granularity is too small.
169Instead execute a transaction where the properties are set in response to some user action or external event.
170</p>
171<p>
172However, unlike database transactions, you do not need to conduct a transaction in order to access any state.
173All JavaScript objects are in memory, so you can look at their properties at any time that it would make sense to do so.
174But when you want to make state changes to a <a>Diagram</a> or a <a>GraphObject</a> or a <a>Model</a> or a JavaScript object in a model,
175do so within a transaction.
176</p>
177<p>
178The only exception is that transactions are unnecessary when initializing a model or a diagram before assigning
179the model to the <a>Diagram.model</a> property.
180(A Diagram only gets access to an UndoManager via the Model, the <a>Model.undoManager</a> property.)
181</p>
182<p>
183Furthermore many event handlers and listeners are already executed within transactions
184that are conducted by <a>Tool</a>s or <a>CommandHandler</a> commands,
185so you often will not need to start and commit a transaction within such functions.
186Read the API documentation for details about whether a function is called within a transaction.
187For example, setting <a>GraphObject.click</a> to an event handler to respond to a click on an object
188needs to perform a transaction if it wants to modify the model or the diagram.
189Most custom click event handlers do not change the diagram but instead update some HTML.
190</p>
191<p>
192But implementing an "ExternalObjectsDropped" <a>DiagramEvent</a> listener, which usually does want to
193modify the just-dropped Parts in the <a>Diagram.selection</a>, is called within the <a>DraggingTool</a>'s
194transaction, so no additional start/commit transaction calls are needed.
195</p>
196<p>
197Finally, some customizations, such as the <a>Node.linkValidation</a> predicate, should not modify the diagram or model at all.
198</p>
199<p>
200Both model changes and diagram changes are recorded in the <a>UndoManager</a>
201only if the model's <a>UndoManager.isEnabled</a> has been set to true.
202If you do not want the user to be able to perform undo or redo and also prevent the recording of any <a>Transaction</a>s,
203but you still want to get "Transaction"-type <a>ChangedEvent</a>s because you want to update a database,
204you can set <a>UndoManager.maxHistoryLimit</a> to zero.
205</p>
206<p>
207To better understand the relationships between objects and transactions in memory, look at this diagram:
208<p>
209<pre class="lang-js" id="transactionsDiagram" style="display:none"><code>
210 diagram.nodeTemplate =
211 $(go.Node, "Auto",
212 { scale : 1.6, isShadowed: true },
213 new go.Binding("location", "pos", go.Point.parse),
214 { locationSpot: go.Spot.Center, portId: "NODE" },
215 $(go.Shape, "RoundedRectangle",
216 { fill: "white", portId: "SHAPE" },
217 new go.Binding("fill", "color"),
218 new go.Binding("strokeWidth", "strokeW")),
219 $(go.TextBlock,
220 { margin: 4, portId: "TEXTBLOCK" },
221 new go.Binding("text", "txt"))
222 );
223
224 // Represents the nodeDataArray for the two nodes
225 diagram.nodeTemplateMap.add("dataNode",
226 $(go.Node, "Auto",
227 {
228 locationSpot: go.Spot.Center,
229 scale: 1.2,
230 selectionAdorned: true,
231 fromSpot: go.Spot.AllSides,
232 toSpot: go.Spot.AllSides,
233 isShadowed: true
234 },
235 new go.Binding("location", "pos", go.Point.parse),
236 new go.Binding("toSpot", "tSpot"),
237 new go.Binding("fromSpot", "fSpot"),
238 $(go.Shape, "Rectangle",
239 { fill: "white" }),
240 $(go.Panel, "Vertical",
241 { defaultStretch: go.GraphObject.Horizontal },
242 $(go.TextBlock, headerStyle(), // Header:
243 {portId: "HEADER" },
244 new go.Binding("text", "head")),
245 $(go.Shape, "LineH", { height: 1, stretch: go.GraphObject.Fill }),
246 $(go.TextBlock, textStyle(), // Location:
247 { portId: "ROW1" },
248 new go.Binding("text", "txt1")),
249 $(go.Shape, "LineH", { height: 1, stretch: go.GraphObject.Fill }),
250 $(go.TextBlock, textStyle(), // Fill:
251 { portId: "ROW2" },
252 new go.Binding("text", "txt2"))
253 )
254 )
255 );
256
257 diagram.nodeTemplateMap.add("dataNodeChanged",
258 $(go.Node, "Auto",
259 {
260 locationSpot: go.Spot.Center,
261 scale: 1.2,
262 selectionAdorned: true,
263 fromSpot: go.Spot.AllSides,
264 toSpot: go.Spot.AllSides,
265 isShadowed: true
266 },
267 new go.Binding("location", "pos", go.Point.parse),
268 new go.Binding("toSpot", "tSpot"),
269 new go.Binding("fromSpot", "fSpot"),
270 $(go.Shape, "Rectangle",
271 { fill: "white" }),
272 $(go.Panel, "Vertical",
273 { defaultStretch: go.GraphObject.Horizontal },
274 $(go.TextBlock, headerStyle(), // Header:
275 {portId: "HEADER" },
276 new go.Binding("text", "head")),
277 $(go.Shape, "LineH", { height: 1, stretch: go.GraphObject.Fill }),
278 $(go.TextBlock, textStyle(), // Location:
279 { portId: "ROW1" },
280 new go.Binding("text", "txt1")),
281 $(go.Shape, "LineH", { height: 1, stretch: go.GraphObject.Fill }),
282 $(go.TextBlock, textStyle(), // Fill:
283 { portId: "ROW2" },
284 new go.Binding("text", "txt2")),
285 $(go.Shape, "LineH", { height: 1, stretch: go.GraphObject.Fill }),
286 $(go.TextBlock, textStyle(), // Text:
287 { portId: "ROW3" },
288 new go.Binding("text", "txt3")),
289 )
290 )
291 );
292
293 diagram.linkTemplateMap.add("dataNode", // Links from dataNode to Nodes
294 $(go.Link,
295 { routing: go.Link.Orthogonal, corner: 5 },
296 $(go.Shape, { stroke: "gray", strokeWidth: 2 }),
297 $(go.Shape, { toArrow: "Standard", stroke: "gray", fill: "gray" })
298 ));
299
300 diagram.nodeTemplateMap.add("title",
301 $(go.Node, "Auto",
302 new go.Binding("location", "pos", go.Point.parse),
303 $(go.TextBlock,
304 { font: "bold 25pt sans-serif", textAlign: "center"},
305 new go.Binding("text", "txt"))
306 ));
307
308 diagram.nodeTemplateMap.add("nodeDataArray",
309 $(go.Node, "Auto",
310 {
311 locationSpot: go.Spot.Center,
312 scale: 1.2,
313 selectionAdorned: true,
314 fromSpot: go.Spot.AllSides,
315 toSpot: go.Spot.AllSides,
316 shadowColor: "#C5C1AA"
317 },
318 new go.Binding("location", "pos", go.Point.parse),
319 $(go.Shape, "Rectangle", { fill: "lightgray" }),
320 $(go.Panel, "Vertical",
321 { defaultStretch: go.GraphObject.Horizontal },
322 $(go.TextBlock, headerStyle(),
323 { portId: "HEADER", text: "nodeDataArray" }),
324 $(go.Shape, "LineH", { height: 1, stretch: go.GraphObject.Fill }),
325 $(go.TextBlock, textStyle(),
326 { portId: "dataNode1", desiredSize: new go.Size(NaN,16) }),
327 $(go.Shape, "LineH", { height: 1, stretch: go.GraphObject.Fill }),
328 $(go.TextBlock, textStyle(),
329 { portId: "dataNode2", desiredSize: new go.Size(NaN,16) })
330 )
331 ));
332
333 diagram.linkTemplateMap.add("Data",
334 $(go.Link,
335 { corner: 10, routing: go.Link.Orthogonal },
336 new go.Binding("curviness"),
337 $(go.Shape, { stroke: "gray" , strokeWidth: 2 }),
338 $(go.Shape, { toArrow: "Standard", fill: "gray", stroke: "gray", strokeWidth: 2 }),
339 $(go.TextBlock, { font: "bold 12pt Courier", segmentOffset: new go.Point(0, -10) },
340 new go.Binding("text", "label"),
341 new go.Binding("segmentOffset", "offset"))
342 ));
343
344 diagram.scale = 0.8;
345
346 var model = new go.GraphLinksModel();
347 model.linkFromPortIdProperty = "fPID";
348 model.linkToPortIdProperty = "tPID"
349
350 model.nodeDataArray = [
351 { key: 1, txt: "Diagram", color: "white", pos: "15 305"},
352 { key: 2, txt: "Model", color: "white", pos: "215 305"},
353 { key: 3, category: "dataNode", pos: "215 440", head: "Node Data Array", txt1: "nodeDataArray[0]", txt2: "nodeDataArray[1]"},
354 { key: 4, pos: "215 187", color: "white", txt: "UndoManager"},
355 { key: 5, pos: "215, 50", category: "dataNode", head: "List of Transactions", txt1: "history[0]", txt2: "history[1]"},
356 { key: 6, pos: "630, 230", category: "dataNode", head: "List of ChangedEvents", txt1: "changes[0]", txt2: "changes[1]", fSpot: go.Spot.RightSide},
357 { key: 7, pos: "15, 561", txt: "Alpha", color: "palegreen"},
358 { key: 8, category: "dataNode", pos: "510 590", head: "Node Data", txt1: "color: \"palegreen\"", txt2: "text: \"Alpha\""},
359 { key: 9, category: "dataNodeChanged", pos: "630 422", head: "ChangedEvent", txt1: "propertyName: \"color\"", txt2: "newValue: \"palegreen\"", txt3: "oldValue: \"red\""},
360 { key: 10, category: "dataNodeChanged", pos: "530, 60", head: "Transaction", txt1: "name: \"change color\"", txt2: "isComplete: true", txt3: "changes: . . ."},
361 ];
362 model.linkDataArray = [
363 { from: 1, to: 2, category: "Data", label: ".model", offset: new go.Point(12, 14)},
364 { from: 2, to: 4, category: "Data", label: ".undoManager", offset: new go.Point(-10, 60)},
365 { from: 1, to: 4, category: "Data", label: ".undoManager", offset: new go.Point(0, -63)},
366 { from: 2, tPID: "HEADER", to: 3, category: "Data", label: ".nodeDataArray", offset: new go.Point(0, -72)},
367 { from: 4, to: 5, category: "Data", label: ".history", offset: new go.Point(0, -45)},
368 { from: 5, fPID: "ROW1", tPID: "HEADER", to: 10, category: "Data", label: "history[0]", offset: new go.Point(35, 10)},
369 { from: 1, to: 7, category: "Data", curviness: -70},
370 { from: 7, tPID: "HEADER", to: 8, category: "Data", curviness: -70, label: ".data", offset: new go.Point(-70, -10)},
371 { from: 3, tPID: "HEADER", fPID: "ROW1", to: 8, category: "Data", label: "nodeDataArray[0]", offset: new go.Point(-15, -85)},
372 { from: 6, to: 9, fPID: "ROW2", category: "Data", label: "changes[1]", offset: new go.Point(0, 54)},
373 { from: 9, to: 8, category: "Data", label: ".object", offset: new go.Point(-10, -13)},
374 { from: 10, to: 6, fPID: "ROW3", category: "Data", label: ".changes", offset: new go.Point(-10, 13)},
375 ];
376
377 diagram.model = model;
378
379 // Formatting
380 function headerStyle() {
381 return {
382 margin: 3,
383 font: "bold 12pt sans-serif",
384 minSize: new go.Size(140, 16),
385 maxSize: new go.Size(120, NaN),
386 textAlign: "center"
387 };
388 }
389 function textStyle() {
390 return {
391 margin: 3,
392 font: "italic 10pt sans-serif",
393 minSize: new go.Size(16, 16),
394 maxSize: new go.Size(160, NaN),
395 textAlign: "left"
396 };
397 }
398</code></pre>
399<script>goCode("transactionsDiagram", 650, 550)</script>
400<p>
401A typical case for using transactions is when some command makes a change to the model.
402</p>
403<pre class="lang-js" id="transaction"><code>
404 // define a function named "addChild" that is invoked by a button click
405 addChild = function() {
406 var selnode = diagram.selection.first();
407 if (!(selnode instanceof go.Node)) return;
408 diagram.commit(function(d) {
409 // have the Model add a new node data
410 var newnode = { key: "N" };
411 d.model.addNodeData(newnode); // this makes sure the key is unique
412 // and then add a link data connecting the original node with the new one
413 var newlink = { from: selnode.data.key, to: newnode.key };
414 // add the new link to the model
415 d.model.addLinkData(newlink);
416 }, "add node and link");
417 };
418
419 diagram.nodeTemplate =
420 $(go.Node, "Auto",
421 $(go.Shape, "RoundedRectangle", { fill: "whitesmoke" }),
422 $(go.TextBlock, { margin: 5 },
423 new go.Binding("text", "key"))
424 );
425
426 diagram.layout = $(go.TreeLayout);
427
428 var nodeDataArray = [
429 { key: "Alpha" },
430 { key: "Beta" }
431 ];
432 var linkDataArray = [
433 { from: "Alpha", to: "Beta" }
434 ];
435 diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
436 diagram.model.undoManager.isEnabled = true;
437</code></pre>
438<p>
439 In the following example, select a node and then click the button.
440 The addChild function adds a link connecting the selected node to a new node.
441 When no Node is selected, nothing happens.
442</p>
443<button onclick="addChild()">addChild() to selected Node</button>
444<script>goCode("transaction", 600, 200)</script>
445
446<h2 id="SupportUndoManager">Supporting the UndoManager</h2>
447<p>
448Changes to JavaScript data properties do not automatically result in any notifications that can be observed.
449Thus when you want to change the value of a property in a manner that can be undone and redone,
450you should call <a>Model.setDataProperty</a> (or <a>Model.set</a>, which is an abbreviation for that method).
451This will get the previous value for the property, set the property to the new value, and
452call <a>Model.raiseDataChanged</a>, which will also automatically update any target bindings in the Node
453corresponding to the data.
454</p>
455<pre class="lang-js" id="changingData"><code>
456 diagram.nodeTemplate =
457 $(go.Node, "Auto",
458 $(go.Shape, "RoundedRectangle", { fill: "whitesmoke" }),
459 $(go.TextBlock, { margin: 5 },
460 new go.Binding("text", "someValue")) // bind to the "someValue" data property
461 );
462
463 var nodeDataArray = [
464 { key: "Alpha", someValue: 1 }
465 ];
466 diagram.model = new go.GraphLinksModel(nodeDataArray);
467 diagram.model.undoManager.isEnabled = true;
468
469 // define a function named "incrementData" callable by onclick
470 incrementData = function() {
471 diagram.model.commit(function(m) {
472 var data = m.nodeDataArray[0]; // get the first node data
473 m.set(data, "someValue", data.someValue + 1);
474 }, "increment");
475 };
476</code></pre>
477<p>
478Move the node around.
479Click on the button to increase the value of the "someValue" property on the first node data.
480Click to focus in the Diagram and then Ctrl-Z and Ctrl-Y to undo and redo the moves and value changes.
481</p>
482<button onclick="incrementData()" >incrementData()</button>
483<script>goCode("changingData", 250, 150)</script>
484
485 </div>
486 </div>
487
488 <div class="bg-nwoods-primary">
489 <section class="max-w-screen-lg text-white container mx-auto py-2 px-12">
490 <p id="version" class="leading-none mb-2 my-4">GoJS</p>
491 </section>
492 </div><footer class="bg-nwoods-primary text-white">
493 <div class="container max-w-screen-lg mx-auto px-8">
494 <div class="w-full py-6">
495
496 <div class="max-w-screen-lg xl:max-w-screen-xl mx-auto px-4 sm:px-6 md:px-8">
497 <ul class="text-sm font-medium pb-14 sm:pb-20 grid grid-cols-1 sm:grid-cols-3 gap-y-10">
498 <li class="list-none row-span-2">
499 <h2 class="text-base font-semibold tracking-wide">GoJS</h2>
500 <ul class="list-none space-y-4 md:space-y-1 px-0">
501 <li>
502 <a href="../samples/index.html">Samples</a>
503 </li>
504 <li>
505 <a href="../learn/index.html">Learn</a>
506 </li>
507 <li>
508 <a href="../intro/index.html">Intro</a>
509 </li>
510 <li>
511 <a href="../api/index.html">API</a>
512 </li>
513 <li>
514 <a href="../changelog.html">Changelog</a>
515 </li>
516 <li>
517 <a href="https://github.com/NorthwoodsSoftware/GoJS">GitHub</a>
518 </li>
519 </ul>
520 </li>
521 <li class="list-none row-span-2">
522 <h2 class="text-base font-semibold tracking-wide">Support</h2>
523 <ul class="list-none space-y-4 md:space-y-1 px-0">
524 <li>
525 <a href="https://www.nwoods.com/contact.html"
526 target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a>
527 </li>
528 <li>
529 <a href="https://forum.nwoods.com/c/gojs">Forum</a>
530 </li>
531 <li>
532 <a href="https://www.nwoods.com/app/activate.aspx?sku=gojs">Activate</a>
533 </li>
534 <li>
535 <a href="https://www.nwoods.com/sales/index.html"
536 target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a>
537 </li>
538 <li>
539 <a href="https://www.youtube.com/channel/UC9We8EoX596-6XFjJDtZIDg">Videos</a>
540 </li>
541 </ul>
542 </li>
543 <li class="list-none row-span-2">
544 <h2 class="text-base font-semibold tracking-wide">Company</h2>
545 <ul class="list-none space-y-4 md:space-y-1 px-0">
546 <li>
547 <a href="https://www.nwoods.com">Northwoods</a>
548 </li>
549 <li>
550 <a href="https://www.nwoods.com/about.html">About Us</a>
551 </li>
552 <li>
553 <a href="https://www.nwoods.com/contact.html">Contact Us</a>
554 </li>
555 <li>
556 <a href="https://twitter.com/northwoodsgo">Twitter</a>
557 </li>
558
559 </ul>
560 </li>
561 </ul>
562
563
564 <p class="text-sm text-gray-100 md:mb-6">
565 Copyright 1998-2021 <a class="text-white" href="https://www.nwoods.com">Northwoods Software</a>
566 </p>
567 </div>
568 </div>
569</footer> </body>
570
571<script async src="https://www.googletagmanager.com/gtag/js?id=UA-1506307-5"></script>
572<script>
573 window.dataLayer = window.dataLayer || [];
574 function gtag(){dataLayer.push(arguments);}
575 gtag('js', new Date()); gtag('config', 'UA-1506307-5');
576 var getOutboundLink = function(url, label) {
577 gtag('event', 'click', {
578 'event_category': 'outbound',
579 'event_label': label,
580 'transport_type': 'beacon'
581 });
582 }
583
584 // topnav
585 var topButton = document.getElementById("topnavButton");
586 var topnavList = document.getElementById("topnavList");
587 topButton.addEventListener("click", function() {
588 this.classList.toggle("active");
589 topnavList.classList.toggle("hidden");
590 document.getElementById("topnavOpen").classList.toggle("hidden");
591 document.getElementById("topnavClosed").classList.toggle("hidden");
592 });
593</script>
594 <script src="../assets/js/prism.js"></script>
595 <script src="../release/go.js"></script>
596 <script src="../assets/js/goDoc.js"></script>
597 <script>
598 document.addEventListener("DOMContentLoaded", function() {
599 if (window.go) document.getElementById('version').textContent = "GoJS version " + go.version;
600 if (window.goDoc) window.goDoc();
601 var d = window.diagrams;
602 for (var i = 0; i < d.length; i++) {
603 var dargs = d[i];
604 goCodeExecute(dargs[0], dargs[1], dargs[2], dargs[3], dargs[4]);
605 }
606 if (window.extra) window.extra();
607 });
608 </script>
609</html>