Issue when add port to a node

The following code shows two nodes Alpha and Beta. Since the node itself is fromLinkable and toLinkable, when I dragged from the non-text area in Alpha and dropped to Beta, a link was created from Alpha to Beta (since they were not linked by default). Once the link has been created, when I dragged from the non-text area in Alpha again, I was no longer able to drop to Beta, which means that I could only create a single link from Alpha to Beta, which is good.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- <div
      id="myDiagramDiv"
      style="border: solid 1px black; width: 100%; height: 700px"
    ></div> -->
    <div style="width: 100%; display: flex; justify-content: space-between">
      <div
        id="myPaletteDiv"
        style="
          width: 105px;
          margin-right: 2px;
          background-color: whitesmoke;
          border: solid 1px black;
        "
      ></div>
      <div
        id="myDiagramDiv"
        style="flex-grow: 1; height: 620px; border: solid 1px black"
      ></div>
    </div>
    <script src="../../release/go-debug.js"></script>
    <script>
      const $ = go.GraphObject.make;

      const init = () => {
        const myDiagram = $(go.Diagram, "myDiagramDiv", {
          "draggingTool.dragsLink": true,
          layout: $(go.LayeredDigraphLayout, {
            layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource,
          }),
        });

        myDiagram.nodeTemplate = $(
          go.Node,
          "Spot",
          {
            locationSpot: go.Spot.Center,
          },
          $(go.Shape, "RoundedRectangle", {
            fill: "white",
            width: 100,
            height: 50,
            portId: "",
            fromLinkable: true,
            toLinkable: true,
            cursor: "pointer",
          }),
          $(
            go.TextBlock, // the text label
            new go.Binding("text", "key"),
            {
              verticalAlignment: go.Spot.Center,
              textAlign: "center",
            },
          ),
        );

        myDiagram.linkTemplate = $(
          go.Link, // the whole link panel
          { routing: go.Link.AvoidsNodes, corner: 10 },
          $(
            go.Shape, // the link shape
            { strokeWidth: 1.5 },
          ),
          $(
            go.Shape, // the arrowhead
            { toArrow: "Standard", stroke: null },
          ),
        );

        const nodeDataArray = [
          {
            key: "Alpha",
          },
          {
            key: "Beta",
          },
        ];

        const linkDataArray = [];

        const model = new go.GraphLinksModel();
        model.nodeDataArray = nodeDataArray;
        model.linkDataArray = linkDataArray;
        myDiagram.model = model;
      };

      window.addEventListener("DOMContentLoaded", init);
    </script>
  </body>
</html>

However, once I added ports to the node (I was using the standard makePort method from many of the GoJS sample examples) and made the node’s fromLinkable and toLinkable to be false, I can add many links by keeping dragging from the right port in Alpha and dropping to the left port in Beta. When I dragged Alpha away, the following screenshot illustrates that there are many links between the two nodes, which is NOT what I want.

Screen Shot 2022-01-29 at 12.57.31 AM

My question is why adding ports causes multiple links can be added between them? I believe that LinkableDuplicates is false by default. The code with the makePort method is posted below. Thanks so much for your time!

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- <div
      id="myDiagramDiv"
      style="border: solid 1px black; width: 100%; height: 700px"
    ></div> -->
    <div style="width: 100%; display: flex; justify-content: space-between">
      <div
        id="myPaletteDiv"
        style="
          width: 105px;
          margin-right: 2px;
          background-color: whitesmoke;
          border: solid 1px black;
        "
      ></div>
      <div
        id="myDiagramDiv"
        style="flex-grow: 1; height: 620px; border: solid 1px black"
      ></div>
    </div>
    <script src="../../release/go-debug.js"></script>
    <script>
      const $ = go.GraphObject.make;

      const init = () => {
        const myDiagram = $(go.Diagram, "myDiagramDiv", {
          "draggingTool.dragsLink": true,
          layout: $(go.LayeredDigraphLayout, {
            layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource,
          }),
        });

        const makePort = (name, spot, output, input) => {
          return $(go.Shape, "Rectangle", {
            fill: "rgba(0, 0, 0, 0.3)",
            stroke: null,
            desiredSize: new go.Size(8, 8),
            alignment: spot,
            alignmentFocus: spot,
            portId: name,
            fromSpot: spot,
            toSpot: spot,
            fromLinkable: output,
            toLinkable: input,
            cursor: "pointer",
          });
        };

        myDiagram.nodeTemplate = $(
          go.Node,
          "Spot",
          {
            locationSpot: go.Spot.Center,
          },
          $(go.Shape, "RoundedRectangle", {
            fill: "white",
            width: 100,
            height: 50,
            // portId: "",
            // fromLinkable: true,
            // toLinkable: true,
            cursor: "pointer",
          }),
          $(
            go.TextBlock, // the text label
            new go.Binding("text", "key"),
            {
              verticalAlignment: go.Spot.Center,
              textAlign: "center",
            },
          ),
          makePort("Left", go.Spot.Left, false, true),
          makePort("Right", go.Spot.Right, true, false),
        );

        myDiagram.linkTemplate = $(
          go.Link, // the whole link panel
          { routing: go.Link.AvoidsNodes, corner: 10 },
          $(
            go.Shape, // the link shape
            { strokeWidth: 1.5 },
          ),
          $(
            go.Shape, // the arrowhead
            { toArrow: "Standard", stroke: null },
          ),
        );

        const nodeDataArray = [
          {
            key: "Alpha",
          },
          {
            key: "Beta",
          },
        ];

        const linkDataArray = [];

        const model = new go.GraphLinksModel();
        model.nodeDataArray = nodeDataArray;
        model.linkDataArray = linkDataArray;
        myDiagram.model = model;
      };

      window.addEventListener("DOMContentLoaded", init);
    </script>
  </body>
</html>

Your code is not really using multiple ports per node because your model hasn’t enabled it. You need to set the GraphLinksModel.linkFromPortIdProperty and linkToPortIdProperty, preferably before you provide any data to the model.

I don’t know why the user can draw multiple links between the same pair of nodes. We’ll investigate.

Hi Walter, really appreciate your quick response! Once I specified linkFromPortIdProperty and linkToPortIdProperty, I could not draw multiple links between the same pair of nodes/ports. It was my bad. Thank you so much!