Trouble with replacing graph elements programmatically using Redux

I am using a Redux store to push graph changes to the Model. I am going with brute force approach of replacing all of the elements (nodes and links) of the model instead of detecting and pushing just the changes (ie: replacing / adding / deleting nodes and links).

The following code does not seem to work correctly. I have looked at the objects and they check out pre and post copy.

diagram.startTransaction(‘replace nodes and links’);
diagram.model.nodeDataArray = [];
diagram.model.linkDataArray = [];
diagram.commitTransaction(‘replace nodes and links’);

diagram.startTransaction(‘replace nodes’);
diagram.model.addNodeDataCollection(copyArrayOfObjects(getStore().getState().objects))
diagram.model.addLinkDataCollection(copyArrayOfObjects(getStore().getState().connections))
diagram.commitTransaction(‘replace nodes’);

Is there a different way I am supposed to do this? The graph updates when i add notes but not when I add links.

I’m not familiar with Redux. Are you saying that copyArrayOfObjects(getStore().getState().connections) is correctly returning an Array of Objects whose from and to properties are referring to the same keys as declared by the just-loaded Array of node Objects?

This is the value of the array passed to addLinkDataCollection method as logged in the Chromes Browser debug console.

[Object, Object]
0: Objectfrom: 99
fromPort: "Out"to: 98
toPort: “A”
proto: Object
1: Object
from: 1
fromPort: “Out”
to: 99
toPort: “B”
proto: Object
length: 2
proto: Array[0]

this is the value of the array sent to the addNodeDataCollection method

[Object, Object, Object]
0: Object
category: “detailed”
key: 99
text: “Foo”
proto: Object
1: Object
category: “detailed”
key: 98
text: “Foo4”
proto: Object
2: Object
category: “detailed”
key: 1
loc: K
name: “pemaButton”
text: “pemaButton”
type: “Amplifer”
proto: Object
length: 3
proto: Array[0]

Sorry looks like my formating got stripped out

this is the template I am using that defines the ports for these nodes that are being added

var advNodeTemplate = (go.Node, "Auto", (go.Shape,
{
fill: (go.Brush, "Linear", { 0: "#CCCCCC", 1: "#333333" }), stroke: "white", strokeWidth: 2, }), new go.Binding("location", "loc"), (go.Panel, “Table”,
(go.RowColumnDefinition, { column: 0, alignment: go.Spot.Left}), (go.RowColumnDefinition,
{ column: 2, alignment: go.Spot.Right }),
(go.TextBlock, // the node title { column: 0, row: 0, columnSpan: 3, alignment: go.Spot.Center, font: "bold 10pt sans-serif", margin: new go.Margin(4, 2) }, new go.Binding("text", "text")), (go.Panel, “Horizontal”,
{ column: 0, row: 1 },
(go.Shape, // the "A" port { width: 8, height: 8, portId: "A", toSpot: go.Spot.Left, fromLinkable: false, toLinkable: true, toMaxLinks: 1, fromMaxLinks:1 }), (go.TextBlock, “A”) // “A” port label
),
(go.Panel, "Horizontal", { column: 0, row: 2 }, (go.Shape, // the “B” port
{ width: 8, height: 8, portId: “B”, toSpot: go.Spot.Left, fromLinkable: false, toLinkable: true, toMaxLinks: 1, fromMaxLinks:1}),
(go.TextBlock, "B") // "B" port label ), (go.Panel, “Horizontal”,
{ column: 2, row: 1, rowSpan: 2 },
(go.TextBlock, "Out"), // "Out" port label (go.Shape, // the “Out” port
{ width: 8, height: 8, portId: “Out”, fromSpot: go.Spot.Right, fromLinkable: true, toLinkable: false, toMaxLinks: 1, fromMaxLinks:1})
)
)
);

templmap.add(“detailed”, advNodeTemplate);

Does the following code work?

diagram.startTransaction();
diagram.model.nodeDataArray = copyArrayOfObjects(getStore().getState().objects);
diagram.model.linkDataArray = copyArrayOfObjects(getStore().getState().connections);
diagram.commitTransaction('replace everything');

No it does not,

When I print out the values of
diagram.model.nodeDataArray
diagram.model.linkDataArray
afterward they are both empty arrays, length 0

Strangely when I created a bare bones example using the same template definitions and the same method for replacing the graph nodes and links it works.

Example Supplied here:

https://drive.google.com/file/d/0BxOCdxIStLEHbmU3T2l1STV3ZHc/view?usp=sharing

I am not sure what is happening in my other program.

In my non-working code.

The links will eventually get added but only after I add a new node.

The entire GoJS canvas element is inserted into a div inside a Webix framework element. I would think they would be isolated enough to not cause any issues but I can’t say for certain.

Well, if something is modifying the Arrays that you assign to Model.nodeDataArray or GraphLinksModel.linkDataArray without notifying the model, that’s a problem.

Whenever you modify model data (or Model properties) or Nodes or Links or Diagram properties, you perform all of the changes within a transaction, don’t you?

Walter,

I am overriding the linkTool.insertLink method

var linkTool = diagram.toolManager.linkingTool
linkTool.insertLink = function(fromNode, fromPort, toNode, toPort) {
	 store.getStore().dispatch({
			type:"addConnection", 
			data:{
				from:fromNode.data.key,//here is where I need to access the fromNode key
				to:toNode.data.key,//here is where I need to access the toNode key
				fromPort:fromPort.portId,//here is where I need to access the fromPort id
				toPort:toPort.portId,//here is where I need to access the toPort id
			}	
		})
	return null;
}

I believe the problem is that I am causing a store update in the middle of the insertLink method. The insert link method does not cause the dragged link to be removed until after returning null. Before this happens I update my store which in turns causes the entire diagram to be re-instantiated. Then after that resolves the link removal resolves.

My fix was to add a time delayed call back in javascript. Now the link removal resolves first then my store update resolves and instantiates the graph.

var linkTool = diagram.toolManager.linkingTool
linkTool.insertLink = function(fromNode, fromPort, toNode, toPort) {
	window.setTimeout(function(){
	 store.getStore().dispatch({
			type:"addConnection", 
			data:{
				from:fromNode.data.key,//here is where I need to access the fromNode key
				to:toNode.data.key,//here is where I need to access the toNode key
				fromPort:fromPort.portId,//here is where I need to access the fromPort id
				toPort:toPort.portId,//here is where I need to access the toPort id
			}	
		})
	}, 1000)
	return null;
}

That’s interesting – I wouldn’t have expected the dispatch call to be synchronous. Thanks for the explanation.