Re add the ports to node

Want to know if it is possible to re add the ports to node at later stage. If so could you please provide the sample code

Lets say I have below code which adds ports during node creation and at later stage my ports are getting overridden by some action so I want to re add the original ports back to node.

goObj(go.Node, “Spot”,
{
locationObjectName: “SHAPE”, locationSpot: go.Spot.Center,
resizable: true, resizeObjectName: “PANEL”,
selectionAdorned: false // use a Binding on the Shape.stroke to show selection
},
new go.Binding(“itemArray”, “boundaryEventArray”),
new go.Binding(“location”, “loc”, go.Point.parse).makeTwoWay(go.Point.stringify),
// move a selected part into the Foreground layer, so it isn"t obscured by any non-selected parts
new go.Binding(“layerName”, “isSelected”, function(s:any) { return s ? “Foreground” : “”; }).ofObject(),
goObj(go.Panel, “Auto”,
{
name: “PANEL”,
minSize: new go.Size(_this.ActivityNodeWidth, _this.ActivityNodeHeight),
desiredSize: new go.Size(_this.ActivityNodeWidth, _this.ActivityNodeHeight)
},
), // end Auto Panel
_this.makePort(“T”, go.Spot.Top, true, true),
_this.makePort(“L”, go.Spot.Left, false, true),
_this.makePort(“R”, go.Spot.Right, true, false),
_this.makePort(“B”, go.Spot.Bottom, true, true)
); // end go.Node, which is a Spot Panel with bound itemArray

makePort(name:any, spot:any, output:any, input:any) {
// the port is basically just a small circle
return goObj(go.Shape, “Circle”,
{
fill: null,
stroke: null,
desiredSize: new go.Size(8, 8),
alignment: spot, alignmentFocus: spot, // align the port on the main Shape
portId: name, // declare this object to be a “port”
fromSpot: spot, toSpot: spot, // declare where links may connect at this port
fromLinkable: output, toLinkable: input, // declare whether the user may draw links to/from here
cursor: “pointer” // show a different cursor to indicate potential link point
}
);
}

I’m not sure what you mean by “my ports are getting overridden by some action”. What are those actions?

If you had changed properties on those ports, such as setting GraphObject.opacity or GraphObject.visible, you can just set those properties again. (Remember to make all changes together in a single transaction.)

If you had removed a port (or any GraphObject, really), you can add it or something else back. The only restriction is that you cannot modify the data Bindings of a Part that has already been shown in the diagram, so whatever you add cannot have any Bindings.

A more automatic way to do that is to use Panel.itemArray and Panel.itemTemplate[Map]. GoJS Item Arrays-- Northwoods Software There are several samples that demonstrate this, such as Dynamic Ports.

I have a custom right click menu action which adds new port as shown below
var defaultPort = node.findPort("");
while (node.findPort(“be” + i.toString()) !== defaultPort){
i++;
}
var name = “be” + i.toString();
if (!node.data.boundaryEventArray) {
_this.dmvBPMNDiagram.model.setDataProperty(node.data, “boundaryEventArray”, []); // initialize the Array of port data
}
let stroke:string=“black”;
if(node.data.custom){
stroke=“green”;
}
// create a new port data object
var newportdata = {
portId: name,
eventType: evType,
eventDimension: evDim,
color: “white”,
alignmentIndex: i,
stroke:stroke
};
_this.dmvBPMNDiagram.model.insertArrayItem(node.data.boundaryEventArray, -1, newportdata);
}

_this.dmvBPMNDiagram.model.setDataProperty(node.data, “boundaryEventArray”, []); line at above code is clearing all the ports added during node creation

The node template that you showed above is incomplete. I had assumed that was because you wanted to simplify it so the forum post wouldn’t include unnecessary stuff.

But it is relevant. I think you need to decide whether all of the ports are defined in the item Array. If you really want to define a few of them explicitly in the node template, then don’t allow them to be removed from the node. Only allow those corresponding to items in the Array to be removed or added.

Below is the code related to node creation and adding ports during node creation

`protected createActivityNodeTemplate():any{
let _this:any=this;
let activityNodeTemplate:any =
goObj(go.Node, “Spot”,_this.nodeStyle(_this),
{
locationObjectName: “SHAPE”, locationSpot: go.Spot.Center,
resizable: true, resizeObjectName: “PANEL”,
selectionAdorned: false, // use a Binding on the Shape.stroke to show selection
contextMenu: _this.activityNodeMenu,
itemTemplate: _this.boundaryEventItemTemplate
},
new go.Binding(“itemArray”, “boundaryEventArray”),
new go.Binding(“location”, “loc”, go.Point.parse).makeTwoWay(go.Point.stringify),
// move a selected part into the Foreground layer, so it isn"t obscured by any non-selected parts
new go.Binding(“layerName”, “isSelected”, function(s:any) { return s ? “Foreground” : “”; }).ofObject(),
goObj(go.Panel, “Auto”,
{
name: “PANEL”,
minSize: new go.Size(_this.ActivityNodeWidth, _this.ActivityNodeHeight),
desiredSize: new go.Size(_this.ActivityNodeWidth, _this.ActivityNodeHeight)
},
new go.Binding(“desiredSize”, “size”, go.Size.parse).makeTwoWay(go.Size.stringify),
goObj(go.Panel, “Spot”,
goObj(go.Shape, “RoundedRectangle”, // the outside rounded rectangle
{
name: “SHAPE”,
fill: _this.ActivityNodeFill, stroke: _this.ActivityNodeStroke,
parameter1: 10 // corner size
},
new go.Binding(“fill”, “color”),
new go.Binding(“strokeWidth”, “isCall”,
function(s:any)
{
return s ? _this.ActivityNodeStrokeWidthIsCall : _this.ActivityNodeStrokeWidth;
}
)
),
// task icon
goObj(go.Shape, “BpmnTaskScript”, // will be None, Script, Manual, Service, etc via converter
{
alignment: new go.Spot(0, 0, 5, 5), alignmentFocus: go.Spot.TopLeft,
width: 22, height: 22
},
new go.Binding(“fill”, “taskType”, _this.nodeActivityTaskTypeColorConverter),
new go.Binding(“figure”, “taskType”, _this.nodeActivityTaskTypeConverter)
), // end Task Icon
_this.makeMarkerPanel(false, 1,_this) // sub-process, loop, parallel, sequential, ad doc and compensation markers
), // end main body rectangles spot panel
goObj(go.TextBlock, // the center text
{
alignment: go.Spot.Center, textAlign: “center”, margin: 12,
editable: true,
font:_this.defaultFont
},
new go.Binding(“text”).makeTwoWay()
)
), // end Auto Panel
_this.makePort(“T”, go.Spot.Top, true, true),
_this.makePort(“L”, go.Spot.Left, false, true),
_this.makePort(“R”, go.Spot.Right, true, false),
_this.makePort(“B”, go.Spot.Bottom, true, true)
); // end go.Node, which is a Spot Panel with bound itemArray
return activityNodeTemplate;
}

Below is the Item Template that adds a port on custom right click menu action

`protected createBoundaryEventItemTemplate():any{
let _this:any=this;
let boundaryEventItemTemplate:any =
goObj(go.Panel, “Spot”,
{
contextMenu: _this.boundaryEventMenu,
alignmentFocus: go.Spot.Center,
fromLinkable: true, toLinkable: false,
cursor: “pointer”, fromSpot: go.Spot.Bottom,
fromMaxLinks: 1, toMaxLinks: 0
},
new go.Binding(“portId”, “portId”),
new go.Binding(“alignment”, “alignmentIndex”, ((s:any)=>_this.nodeActivityBESpotConverter(s))),
goObj(go.Shape, “Circle”,
{
margin:2,desiredSize: new go.Size(_this.EventNodeSize0.5, _this.EventNodeSize0.5)
},
new go.Binding(“strokeDashArray”, “eventDimension”, function(s:any){ return (s === 6) ? [4, 2] : null;}),
new go.Binding(“stroke”, “stroke”),
new go.Binding(“fromSpot”, “alignmentIndex”,
function(s:any) {
// nodeActivityBEFromSpotConverter, 0 & 1 go on bottom, all others on top of activity
if (s < 2)
return go.Spot.Bottom;
return go.Spot.Top;
}
),
new go.Binding(“fill”, “color”)
),
goObj(go.Shape, “Circle”,
{
alignment: go.Spot.Center,
desiredSize: new go.Size(_this.EventNodeInnerSize0.5, _this.EventNodeInnerSize0.5), fill: null
},
new go.Binding(“strokeDashArray”, “eventDimension”, function(s:any){ return (s === 6) ? [4, 2] : null; })
),
goObj(go.Shape, “NotAllowed”,
{
alignment: go.Spot.Center,
desiredSize: new go.Size(_this.EventNodeSymbolSize0.5, _this.EventNodeSymbolSize0.5), fill: “white”
},
new go.Binding(“figure”, “eventType”, _this.nodeEventTypeConverter)
)
);
return boundaryEventItemTemplate;
}``

When I inspected diagram data found that ports added during node creation are not added to “itemArray” and are only shown as node.ports iterator. I am not able to figure out a way to not to remove these ports on right click menu action which initializes the “itemArray” data(old ports are removed during this time) if it is null and add new port to “itemArray” data

Note: During node creation I need to add the ports because I am showing the ports on mouse hover of 4 sides of the node

That’s a lot of unformatted code.

I suggest that you make sure that the nodedata.boundaryEventArray hold all of the port descriptor objects that you want your node to show. That’s what the Dynamic Ports and Pipes samples do. Pipes And remove the definition and uses of makePort.

I was thinking the same but my issue is I want to add default ports as soon as node gets created and I don’t want to add port information to nodeDataArray because I already have some exported data and it may fail while importing that data. Could you please share if you have any sample.

Did you want your persisted model data to possibly have empty arrays of ports?

In that case when you load the model data you could blindly add a port at the beginning of each port array, and then you can assign the Diagram.model, causing all created nodes to have at least one port per array.

Then when it is time to save the model data you can first blindly strip out all of the first port data objects in all of the port arrays, followed by actually saving the model.