Need direction binding link data

Hi All,
I am attempting something that I don’t know if I can or should do. I want to bind custom properties in the link to those of the port and persist that data in the LinkDataArray for use elsewhere. The additional port properties are bound twoway() so edits to them would ideally update the link data as well.

Ideally my link data which should derive from the port data would look like:

{"from":"unit Four", "to":"unit Three", "fromPort":"right0", "toPort":"left0",
     //that's the stock approach that is in all examples. I need to extend that to include the following data derived from the additional port properties 
    "fromPortName":"Fred", "fromPortConn":"Wilma", "toPortName":"Barny", "toPortConn":"Betty"}

I am creating additional port properties:

 function addPort(side) {
    myDiagram.startTransaction("addPort");
    myDiagram.selection.each(function(node) {
      // skip any selected Links
      if (!(node instanceof go.Node)) return;
      // compute the next available index number for the side
      var i = 0;
      while (node.findPort(side + i.toString()) !== node) i++;
      // now this new port name is unique within the whole Node because of the side prefix
      var name = side + i.toString();
      // get the Array of port data to be modified
      var arr = node.data[side + "Array"];
      if (arr) {
        // create a new port data object
        var newportdata = {
          portId: name,
          portColor: go.Brush.randomColor(),
		  portName: "Name" + i.toString(),
		  portConn: "Conn" + i.toString()
		  //I don't understand or can't find reference to the method or concept below
          // if you add port data properties here, you should copy them in copyPortData above
        };
        // and add it to the Array of port data
        myDiagram.model.insertArrayItem(arr, -1, newportdata);
      }
    });
    myDiagram.commitTransaction("addPort");
  }

I have the archtypeLinkData as:

myDiagram.toolManager.linkingTool.archetypeLinkData = {

	fromPortName: 'SomePortName',
	fromPortConn: 'SomePortConn',
    toPortName: 'SomePortName',
	toPortConn: 'SomePortConn'};

Any guidance or direction you can point me in would be appreciated.
Thanks!

I don’t understand the motivation. Are you expecting to copy information from a link’s connected port data to the link data? No matter how many links there are connected to a particular port? That sounds like a lot of duplicated information.

Did you expect to copy that port information when the connection is made? If the link is reconnected, the information from the new port will overwrite the corresponding properties on the link data object? If so, what you could do (instead of using Bindings) is to implement Link.fromPortChanged and Link.toPortChanged event handlers to copy the information.

I haven’t tried this, but it would be something like:

        toPortChanged: function(link, oldport, newport) {
            link.data.toPortName = (newport ? newport.data.portName : "");
            link.data.toPortConn = (newport ? newport.data.portConn : "");
        }

If there are any data Bindings whose source is “toPortName” or “toPortConn”, you’d probably want to call Model.setDataProperty instead of assigning that property directly.

The motivation is to have convenience fields for lists. I am open to any suggestions though. I am still favoring the databinding approach if I can make it work.

I implemented the

It appears that on link creation the Link.data array is not yet created. Upon re-link it appears to work fine. I had to modify it thusly to test the relink:

function fromPortChanged(link, oldport, newport) {
	if(link.data === null)return; //always null on link creation
    link.data.fromPortName = (newport ? newport.data.portName : "");
    link.data.fromPortConn = (newport ? newport.data.portConn : "");
};

Back to the databinding that does not work. In my linktemplate I tried:

 myDiagram.linkTemplate =
      $$(CustomLink,  // defined below
        {
          routing: go.Link.AvoidsNodes,
          corner: 4,
          curve: go.Link.JumpGap,
          reshapable: true,
          resegmentable: true,
          relinkableFrom: true,
          relinkableTo: true,
	      fromPortChanged: fromPortChanged //my function to update port data
        },
        new go.Binding("points").makeTwoWay(),
		//the following does not work. I cannot tell if the I am addressing the 
		//both items are in the data arrays of the respective objects. 
		//fromPortName is in the data array of the link and portName is in the data of the port.
		//I would like changes to the diagram to reflect in the linkdata
		new go.Binding("fromPortName","portName").makeTwoWay(),
        $$(go.Shape, { stroke: "#2F4F4F", strokeWidth: 2 }),
		
		//playing around with link text
		$$(go.TextBlock, "from", { segmentIndex: 1, segmentFraction: 0 , segmentOffset: new go.Point(0, -10)}),
		$$(go.TextBlock, "to", { segmentIndex: -1, segmentFraction: 0.5 , segmentOffset: new go.Point(0, -10) })
      );

Thanks for the help so far.

The binding new go.Binding("fromPortName", "portName").makeTwoWay() provides a data binding between the Link.fromPortName property (as the target)
and the portName property on the Link.data object (as the source).

Unfortunately, there is no “fromPortName” property that is defined on the Link class, so that would not be a useful target. And because the Binding is TwoWay, there is no way that there can be a value going from the Link.fromPortName property back to the data.portName property.

And of course that data.portName property is operating on the Link.data, not on any Node.data.

So just for clarification, is there no way to bind to the custom properties in the link.data array or the port.data array?

Secondly, is this bad form:

myDiagram.addDiagramListener("LinkDrawn", function(e) {
    	var link = e.subject.part;
    //Bad form????   
	link.data.fromPortName = link.fromPort.data.portName;
    	
 });

Or should I use the Model.setDataProperty.
What are the ramifications if any.

Thanks again for the help.

“custom properties in the link.data array”: if I understand you correctly, that is the default behavior for a Binding – binding some Link property to the value of some Link.data property.

It is possible to use a binding conversion function to depend on the port data, but it won’t automatically be updated when the port data properties are changed, because the dependency of a Binding on a Link will not know that the real source of the data is on some other object associated with some other Part.

Secondly, yes, you can do that. The differences between the “LinkDrawn” DiagramEvent listener and the Link.toPortChanged event handler are:

  • the former is raised only when the user draws a new link, by the LinkingTool’s operation
  • the former is not raised when the user reconnects an existing link (use the “LinkRelinked” DiagramEvent for that case)
  • the latter is raised no matter how the port is changed, not just by user action, but by programmatic changes as well

Ok thanks I think that gets me started.