Unable to add link

Hi,

I wrote a custom property based on which the no. of inputs of the node changes.
When i give the property value as 3 then the no.of inputs ports changes to 3.

The problem here is after adding the new port, i am unable to add link from output port of Input 1 to input port(newly added port) of AND gate. I am able to do vice versa.

Can you please let me know what could be the problem here?

Here is the whole file.

function init() {
  var $ = go.GraphObject.make;  // for conciseness in defining templates

  myDiagram =
    $(go.Diagram, "myDiagramDiv",  // create a new Diagram in the HTML DIV element "myDiagramDiv"
      {
        initialContentAlignment: go.Spot.Center,
        allowDrop: true,  // Nodes from the Palette can be dropped into the Diagram
        "draggingTool.isGridSnapEnabled": true,  // dragged nodes will snap to a grid of 10x10 cells
        "undoManager.isEnabled": true
      });

  // when the document is modified, add a "*" to the title and enable the "Save" button
  myDiagram.addDiagramListener("Modified", function(e) {
    var button = document.getElementById("saveModel");
    if (button) button.disabled = !myDiagram.isModified;
    var idx = document.title.indexOf("*");
    if (myDiagram.isModified) {
      if (idx < 0) document.title += "*";
    } else {
      if (idx >= 0) document.title = document.title.substr(0, idx);
    }
  });

  // creates relinkable Links that will avoid crossing Nodes when possible and will jump over other Links in their paths
  myDiagram.linkTemplate =
    $(go.Link,
      {
        routing: go.Link.AvoidsNodes,
        curve: go.Link.JumpOver,
        corner: 3,
        relinkableFrom: true, relinkableTo: true,
        selectionAdorned: false, // Links are not adorned when selected so that their color remains visible.
        shadowOffset: new go.Point(0, 0), shadowBlur: 5, shadowColor: "blue",
        toolTip:
          $(go.Adornment, "Auto",
            $(go.Shape, { fill: "lightyellow" }),
            $(go.TextBlock, { margin: 4 },
              new go.Binding("text"))
          )
      },
      new go.Binding("isShadowed", "isSelected").ofObject(),
      $(go.Shape,
        { name: "SHAPE", strokeWidth: 2 },
        new go.Binding("stroke").makeTwoWay())
    );

  // node template helpers
  // define some common property settings

  function nodeStyle() {
    return [new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            new go.Binding("isShadowed", "isSelected").ofObject(),
            {
              selectionAdorned: false,
              shadowOffset: new go.Point(0, 0),
              shadowBlur: 15,
              shadowColor: "blue",
              toolTip:
                $(go.Adornment, "Auto",
                  $(go.Shape, { fill: "lightyellow" }),
                  $(go.TextBlock, { margin: 4 },
                    new go.Binding("text", "", function(d) {
                      var msg = d.key+ ": " + d.category;
                      if (d.text) msg += "\n" + d.text;
                      return msg;
                    }))
                )
            }];
  }

  function shapeStyle() {
    return [
      {
        name: "NODESHAPE",
        fill: "lightgray",
        stroke: "darkslategray",
        desiredSize: new go.Size(40, 40),
        strokeWidth: 2
      },
      new go.Binding("fill").makeTwoWay()
    ];
  }

  function portStyle(input) {
    return {
      desiredSize: new go.Size(6, 6),
      fill: "black",
      fromSpot: go.Spot.Right,
      fromLinkable: !input,
      toSpot: go.Spot.Left,
      toLinkable: input,
      toMaxLinks: 1,
      cursor: "pointer",
      toolTip:
        $(go.Adornment, "Auto",
          $(go.Shape, { fill: "lightyellow" }),
          $(go.TextBlock, { margin: 4 },
            new go.Binding("text", "adornedObject", function(obj) {
              return obj.portId + " on " + obj.part.data.key;
            }).ofObject())
        )
    };
  }

  // define templates for each type of node
  var inputTemplate =
    $(go.Node, "Spot", nodeStyle(),
      $(go.Shape, "Circle", shapeStyle()),
      $(go.Shape, "Rectangle", portStyle(false),  // the only port
        { portId: "", alignment: new go.Spot(1, 0.5) })
    );

  var outputTemplate =
    $(go.Node, "Spot", nodeStyle(),
      $(go.Shape, "Rectangle", shapeStyle()),
      $(go.Shape, "Rectangle", portStyle(true),  // the only port
        { portId: "", alignment: new go.Spot(0, 0.5) })
    );

  var andTemplate =
    $(go.Node, "Spot", nodeStyle(),
      $(go.Panel, "Table",
        $(go.Shape, "AndGate", shapeStyle(), { margin: new go.Margin(0, 0, 0, 3) }),
        $(go.Panel, "Table",
          new go.Binding("itemArray", "inputPorts"),
          {
            margin: new go.Margin(4, 0),
            alignment: go.Spot.Left,
            stretch: go.GraphObject.Vertical,
            rowSizing: go.RowColumnDefinition.ProportionalExtra,
            itemTemplate:
              $(go.Panel, "TableRow",
                $(go.Shape, "Rectangle", portStyle(true), new go.Binding("portId"))
              )
          }
        )
      ),
      $(go.Shape, "Rectangle", portStyle(false),
        { portId: "out", alignment: new go.Spot(1, 0.5) })
    );

  var orTemplate =
    $(go.Node, "Spot", nodeStyle(),
      $(go.Shape, "OrGate", shapeStyle()),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in1", alignment: new go.Spot(0.16, 0.3) }),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in2", alignment: new go.Spot(0.16, 0.7) }),
      $(go.Shape, "Rectangle", portStyle(false),
        { portId: "out", alignment: new go.Spot(1, 0.5) })
    );

  var xorTemplate =
    $(go.Node, "Spot", nodeStyle(),
      $(go.Shape, "XorGate", shapeStyle()),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in1", alignment: new go.Spot(0.26, 0.3) }),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in2", alignment: new go.Spot(0.26, 0.7) }),
      $(go.Shape, "Rectangle", portStyle(false),
        { portId: "out", alignment: new go.Spot(1, 0.5) })
    );

  var norTemplate =
    $(go.Node, "Spot", nodeStyle(),
      $(go.Shape, "NorGate", shapeStyle()),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in1", alignment: new go.Spot(0.16, 0.3) }),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in2", alignment: new go.Spot(0.16, 0.7) }),
      $(go.Shape, "Rectangle", portStyle(false),
        { portId: "out", alignment: new go.Spot(1, 0.5) })
    );

  var xnorTemplate =
    $(go.Node, "Spot", nodeStyle(),
      $(go.Shape, "XnorGate", shapeStyle()),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in1", alignment: new go.Spot(0.26, 0.3) }),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in2", alignment: new go.Spot(0.26, 0.7) }),
      $(go.Shape, "Rectangle", portStyle(false),
        { portId: "out", alignment: new go.Spot(1, 0.5) })
    );

  var nandTemplate =
    $(go.Node, "Spot", nodeStyle(),
      $(go.Shape, "NandGate", shapeStyle()),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in1", alignment: new go.Spot(0, 0.3) }),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in2", alignment: new go.Spot(0, 0.7) }),
      $(go.Shape, "Rectangle", portStyle(false),
        { portId: "out", alignment: new go.Spot(1, 0.5) })
    );

  var notTemplate =
    $(go.Node, "Spot", nodeStyle(),
      $(go.Shape, "Inverter", shapeStyle()),
      $(go.Shape, "Rectangle", portStyle(true),
        { portId: "in", alignment: new go.Spot(0, 0.5) }),
      $(go.Shape, "Rectangle", portStyle(false),
        { portId: "out", alignment: new go.Spot(1, 0.5) })
    );

  // add the templates created above to myDiagram and palette
  myDiagram.nodeTemplateMap.add("input", inputTemplate);
  myDiagram.nodeTemplateMap.add("output", outputTemplate);
  myDiagram.nodeTemplateMap.add("and", andTemplate);
  myDiagram.nodeTemplateMap.add("or", orTemplate);
  myDiagram.nodeTemplateMap.add("xor", xorTemplate);
  myDiagram.nodeTemplateMap.add("not", notTemplate);
  myDiagram.nodeTemplateMap.add("nand", nandTemplate);
  myDiagram.nodeTemplateMap.add("nor", norTemplate);
  myDiagram.nodeTemplateMap.add("xnor", xnorTemplate);

  // share the template map with the Palette
  var palette = new go.Palette("palette");  // create a new Palette in the HTML DIV element "palette"
  palette.nodeTemplateMap = myDiagram.nodeTemplateMap;

  palette.model.nodeDataArray = [
    { category: "input" },
    { category: "output" },
    { category: "and", numInputs: 2, inputPorts: [{ portId: "in1" }, { portId: "in2" }] },
    { category: "or" },
    { category: "xor" },
    { category: "not" },
    { category: "nand" },
    { category: "nor" },
    { category: "xnor" }
  ];

  // support editing the properties of the selected person in HTML
  if (window.Inspector) {
    // Inspector helper function
    function updateNumInputs(name, value) {
      if (name !== "numInputs") return;
      var data = myInspector.inspectedObject.data;
      var inputs = data.inputPorts;
      if (value > inputs.length) {
        while (value > inputs.length) {
          myDiagram.model.addArrayItem(inputs, { portId: "in" + (inputs.length+1).toString() });
        }
      } else if (value < inputs.length) {
        while (value < inputs.length) {
          myDiagram.model.removeArrayItem(inputs, inputs.length - 1);
        }
      }
    }

    myInspector = new Inspector("myInspector", myDiagram,
    {
      properties: {
        "key": { readOnly: true, show: Inspector.showIfPresent },
        "text": { },
        "fill": { type: "color", defaultValue: "lightgray", show: Inspector.showIfNode },
        "stroke": { type: "color", defaultValue: "black", show: Inspector.showIfLink },
        "numInputs": { type: "number", defaultValue: 2, show: Inspector.showIfPresent },
        "inputPorts": { show: false }
      },
      propertyModified: updateNumInputs
    });
  }

  // load the initial diagram
  load();
}

// save a model to and load a model from JSON text, displayed below the Diagram
function save() {
  document.getElementById("mySavedModel").value = myDiagram.model.toJson();
  myDiagram.isModified = false;
}
function load() {
  myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
}
Save Load Diagram Model saved in JSON format:
{ "class": "go.GraphLinksModel", "linkFromPortIdProperty": "fromPort", "linkToPortIdProperty": "toPort", "copiesArrays": true, "copiesArrayObjects": true, "nodeDataArray": [ {"category":"input", "key":"input1", "loc":"-150 -80" }, {"category":"or", "key":"or1", "loc":"-70 0" }, {"category":"not", "key":"not1", "loc":"10 0" }, {"category":"xor", "key":"xor1", "loc":"100 0" }, {"category":"or", "key":"or2", "loc":"200 0" }, {"category":"output", "key":"output1", "loc":"200 -100", "text":"this only has an input port" } ], "linkDataArray": [ {"from":"input1", "fromPort":"out", "to":"or1", "toPort":"in1", "text":"coming from the only input node"}, {"from":"or1", "fromPort":"out", "to":"not1", "toPort":"in"}, {"from":"not1", "fromPort":"out", "to":"or1", "toPort":"in2"}, {"from":"not1", "fromPort":"out", "to":"xor1", "toPort":"in1"}, {"from":"xor1", "fromPort":"out", "to":"or2", "toPort":"in1"}, {"from":"or2", "fromPort":"out", "to":"xor1", "toPort":"in2"}, {"from":"xor1", "fromPort":"out", "to":"output1", "toPort":""} ]}

Hmmm, that seems to be a bug in GoJS. We’re investigating…

Could you try the 1.8.9 beta version that I just uploaded to GoJS - Build Interactive Diagrams for the Web ?

I hope that should fix the problem.

It worked.

Thanks