Dynamic ports for custom template

Hi, i have a node for which i can i add dynamic ports as shown below. i am able to add left and right ports dynamically but not able to add the top and bottom ports in proper spot on the node. Below is the template for the node shown in the picture
myDiagram.nodeTemplateMap.add(“Switch”,
(go.Node, "Horizontal", new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), (go.Panel, “Vertical”,
new go.Binding(“itemArray”, “leftArray”),
{ row: 1, column: 0,
itemTemplate:
(go.Panel, { _side: "left", // internal property to make it easier to tell which side it's on fromSpot: go.Spot.Left, toSpot: go.Spot.Left, fromLinkable: true, toLinkable: true, cursor: "pointer", contextMenu: portMenu }, new go.Binding("portId", "portId"), (go.Shape, “Rectangle”,
{ stroke: null, strokeWidth: 0,
desiredSize: portSize,
margin: new go.Margin(1,0) },
new go.Binding(“fill”, “portColor”))
) // end itemTemplate
}
), // end Vertical Panel
$(go.Shape, “Rectangle”, {
fill: ‘#009CCC’, strokeWidth: 1, stroke: ‘#009CCC’,
width: 6, stretch: go.GraphObject.Vertical, alignment: go.Spot.Left,
// if a user clicks the colored portion of a node, cycle through colors
click: function (e, obj) {
debugger;
myDiagram.startTransaction(“Update node color”);
var newColor = parseInt(obj.part.data.color) + 1;
if (newColor > noteColors.length-1) newColor = 0;
myDiagram.model.setDataProperty(obj.part.data, “stroke”, “#ff0000”);
myDiagram.model.setDataProperty(obj.part.data, “fill”, “#ff0000”);
myDiagram.commitTransaction(“Update node color”);
}
},
new go.Binding(“fill”, “fill”, getNoteColor),
new go.Binding(“stroke”, “stroke”, getNoteColor)
),

    // the Panel holding the top port elements, which are themselves Panels,
    // created for each item in the itemArray, bound to data.topArray
    
    $(go.Panel, "Auto",
      $(go.Shape, "Rectangle", { fill: "white", stroke: '#CCCCCC' }),
      $(go.Panel, "Vertical", 
      new go.Binding("itemArray", "topArray"),
      { row: 0, column: 1,
        itemTemplate:
          $(go.Panel,
            { _side: "top",
              fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
              fromLinkable: true, toLinkable: true, cursor: "pointer",
              contextMenu: portMenu },
            new go.Binding("portId", "portId"),
            $(go.Shape, "Rectangle",
              { stroke: null, strokeWidth: 0,
                desiredSize: portSize,
                margin: new go.Margin(0, 1) },
              new go.Binding("fill", "portColor"))
          )  // end itemTemplate
      }
    ),  // end Horizontal Panel
      $(go.Panel, "Table",  
        { width: 130, minSize: new go.Size(NaN, 50) },
        $(go.Picture,
          { desiredSize: new go.Size(24, 24),
            imageStretch: go.GraphObject.Uniform,
            alignment: go.Spot.Left,
            margin: new go.Margin(6, 8, 6, 10),},
                    new go.Binding("source", "source")),
         $(go.TextBlock,
          {
            name: 'TEXT',
            margin: 6, font: '11px Lato, sans-serif', editable: true,
            stroke: "#000", maxSize: new go.Size(130, NaN),
            alignment: go.Spot.TopRight   
          },
          new go.Binding("text", "comments").makeTwoWay())
      )
    ),
    
    // the Panel holding the right port elements, which are themselves Panels,
    // created for each item in the itemArray, bound to data.rightArray
    $(go.Panel, "Vertical",
      new go.Binding("itemArray", "rightArray"),
      { row: 1, column: 2,
        itemTemplate:
          $(go.Panel,
            { _side: "right",
              fromSpot: go.Spot.Right, toSpot: go.Spot.Right,
              fromLinkable: true, toLinkable: true, cursor: "pointer",
              contextMenu: portMenu },
            new go.Binding("portId", "portId"),
            $(go.Shape, "Rectangle",
              { stroke: null, strokeWidth: 0,
                desiredSize: portSize,
                margin: new go.Margin(1, 0) },
              new go.Binding("fill", "portColor"))
          )  // end itemTemplate
      }
    ),  // end Vertical Panel

    // the Panel holding the bottom port elements, which are themselves Panels,
    // created for each item in the itemArray, bound to data.bottomArray
    $(go.Panel, "Horizontal",
      new go.Binding("itemArray", "bottomArray"),
      { row: 2, column: 1,
        itemTemplate:
          $(go.Panel,  
            { _side: "bottom",
              fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
              fromLinkable: true, toLinkable: true, cursor: "pointer",
              contextMenu: portMenu },
            new go.Binding("portId", "portId"),
            $(go.Shape, "Rectangle",
              { stroke: null, strokeWidth: 0,
                desiredSize: portSize,
                margin: new go.Margin(0, 1) },
              new go.Binding("fill", "portColor"))
          )  // end itemTemplate
      }
    ) 
  ));

Since your code is not formatted and indented properly, it’s hard to read.

However it is clear that you are no longer using a “Table” Panel, when that is what you need and what is used in the Dynamic Ports sample.

myDiagram.nodeTemplateMap.add("Switch",
      $(go.Node, "Horizontal",nodeStyle(),
        new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
        $(go.Panel, "Vertical",
          new go.Binding("itemArray", "leftArray"),
          { row: 1, column: 0,
            itemTemplate:
              $(go.Panel,  
                { _side: "left",  // internal property to make it easier to tell which side it's on
                  fromSpot: go.Spot.Left, toSpot: go.Spot.Left,
                  fromLinkable: true, toLinkable: true, cursor: "pointer",
                  contextMenu: portMenu },
                new go.Binding("portId", "portId"),
                $(go.Shape, "Rectangle",
                  { stroke: null, strokeWidth: 0,
                    desiredSize: portSize,
                    margin: new go.Margin(1,0) },
                  new go.Binding("fill", "portColor"))
              )  // end itemTemplate
          }
        ),  // end Vertical Panel
        $(go.Shape, "Rectangle", {
            fill: '#009CCC', strokeWidth: 1, stroke: '#009CCC',
            width: 6, stretch: go.GraphObject.Vertical, alignment: go.Spot.Left,
            // if a user clicks the colored portion of a node, cycle through colors
            click: function (e, obj) {   
                debugger;
                myDiagram.startTransaction("Update node color");
                var newColor = parseInt(obj.part.data.color) + 1;
                if (newColor > noteColors.length-1) newColor = 0;
                myDiagram.model.setDataProperty(obj.part.data, "stroke", "#ff0000");
                 myDiagram.model.setDataProperty(obj.part.data, "fill", "#ff0000");
                myDiagram.commitTransaction("Update node color");
            }
          },
                           new go.Binding("fill", "fill", getNoteColor),
                           new go.Binding("stroke", "stroke", getNoteColor)
        ), 

        
        // the Panel holding the top port elements, which are themselves Panels,
        // created for each item in the itemArray, bound to data.topArray
        
        $(go.Panel, "Auto",
          $(go.Shape, "Rectangle", { fill: "white", stroke: '#CCCCCC' }),
          $(go.Panel, "Vertical", 
          new go.Binding("itemArray", "topArray"),
          { row: 0, column: 1,
            itemTemplate:
              $(go.Panel,
                { _side: "top",
                  fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
                  fromLinkable: true, toLinkable: true, cursor: "pointer",
                  contextMenu: portMenu },
                new go.Binding("portId", "portId"),
                $(go.Shape, "Rectangle",
                  { stroke: null, strokeWidth: 0,
                    desiredSize: portSize,
                    margin: new go.Margin(0, 1) },
                  new go.Binding("fill", "portColor"))
              )  // end itemTemplate
          }
        ),  // end Horizontal Panel
          $(go.Panel, "Table",  
            { width: 130, minSize: new go.Size(NaN, 50) },
            $(go.Picture,
              { desiredSize: new go.Size(24, 24),
                imageStretch: go.GraphObject.Uniform,
                alignment: go.Spot.Left,
                margin: new go.Margin(6, 8, 6, 10),},
                        new go.Binding("source", "source")),
             $(go.TextBlock,
              {
                name: 'TEXT',
                margin: 6, font: '11px Lato, sans-serif', editable: true,
                stroke: "#000", maxSize: new go.Size(130, NaN),
                alignment: go.Spot.TopRight   
              },
              new go.Binding("text", "comments").makeTwoWay())
          )
        ),
        
        // the Panel holding the right port elements, which are themselves Panels,
        // created for each item in the itemArray, bound to data.rightArray
        $(go.Panel, "Vertical",
          new go.Binding("itemArray", "rightArray"),
          { row: 1, column: 2,
            itemTemplate:
              $(go.Panel,
                { _side: "right",
                  fromSpot: go.Spot.Right, toSpot: go.Spot.Right,
                  fromLinkable: true, toLinkable: true, cursor: "pointer",
                  contextMenu: portMenu },
                new go.Binding("portId", "portId"),
                $(go.Shape, "Rectangle",
                  { stroke: null, strokeWidth: 0,
                    desiredSize: portSize,
                    margin: new go.Margin(1, 0) },
                  new go.Binding("fill", "portColor"))
              )  // end itemTemplate
          }
        ),  // end Vertical Panel

        // the Panel holding the bottom port elements, which are themselves Panels,
        // created for each item in the itemArray, bound to data.bottomArray
        $(go.Panel, "Horizontal",
          new go.Binding("itemArray", "bottomArray"),
          { row: 2, column: 1,
            itemTemplate:
              $(go.Panel,         
                { _side: "bottom",
                  fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
                  fromLinkable: true, toLinkable: true, cursor: "pointer",
                  contextMenu: portMenu },
                new go.Binding("portId", "portId"),
                $(go.Shape, "Rectangle",
                  { stroke: null, strokeWidth: 0,
                    desiredSize: portSize,
                    margin: new go.Margin(0, 1) },
                  new go.Binding("fill", "portColor"))
              )  // end itemTemplate
          }
        ) 
      ));

using the above template i want to add the ports dynamically,

The Dynamic Ports sample demonstrates how to add and remove ports by adding and removing item data from the respective item Arrays. Call Model.addArrayItem, Model.insertArrayItem, or Model.removeArrayItem.