Node template is positioned out of the placeholder

Hi,
My node inside group is positioned out of the whole node template… which is in top left corner of each node… And as mentioned below it should be at the place holder location… tried to realign and made lot of changes, couldn’t figure out the issue am facing to align at the bottom center of the whole node, where first half of template in group is as header for each node and next half is to position the node template @placeholder shape… while using go.placeholder couldn’t move only the node, it is moving together with group…

initDiagram(): go.Diagram {
const $ = go.GraphObject.make;
let dia = $(go.Diagram, {
“undoManager.isEnabled”: true,
“animationManager.isEnabled”: true,
“allowVerticalScroll”: false,
“allowHorizontalScroll”: false,
“allowDelete”: false,
“allowCopy”: false,
“allowClipboard”: false,
“allowInsert”: false,
layout: $(go.GridLayout,
{
spacing: new go.Size(25, 25), // Adjust spacing as needed
wrappingColumn: 5,
}),
mouseDrop: (e) => {
e.diagram.currentTool.doCancel();
},
model: new go.GraphLinksModel(
{
nodeKeyProperty: ‘key’,
linkKeyProperty: ‘key’, // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
nodeCategoryProperty: “category”
}),
});
dia.commandHandler.archetypeGroupData = { key: ‘Group’, isGroup: true };
const CellSize = new go.Size(130, 200);
dia.toolManager.draggingTool.doActivate = function () {
let part = this.diagram.selection.first(); // Get the first selected part
// If the selected part is a node or the “PLACEHOLDER”, allow dragging
if (part instanceof go.Node || part.name === “PLACEHOLDER”) {
go.DraggingTool.prototype.doActivate.call(this);
} else {
// Cancel dragging for other parts (e.g., groups)
this.diagram.currentTool.doCancel();
}
};
// Set up the SelectionMoved event
dia.addDiagramListener(“SelectionMoved”, (e) => {
e.subject.each((part) => {
if (part instanceof go.Node) {
const node = part as go.Node;
const newGroup = node.containingGroup;
if (newGroup) {
console.log(“Node moved to group:”, newGroup.data.key);
// You can handle the group key as needed here
// updateGroupNodeStatus(newGroup);
} else {
console.log(“Node is not inside any group”);
}
}
});
});

dia.groupTemplate = $(go.Group, "Vertical",
  {
    locationObjectName: 'GROUP',
    movable: false,
    background: "transparent",
    layerName: "bgGroup",
    category: "bgGroup",
    locationSpot: go.Spot.Center,
    padding: 5,
    layout: $(go.GridLayout, {
      wrappingColumn: 1,
    }),
    mouseDrop: (e, grp) => {
      if (grp instanceof go.Group && e.diagram.selection.all((n) => !(n instanceof go.Group))) {
        const ok = grp.addMembers(grp.diagram.selection, true);
        if (!ok) grp.diagram.currentTool.doCancel();
      }
    },
    click: (e, obj) => {
      obj.part.isHighlighted = true,
        console.log('obj key is ', obj.part.data.key)
    }
  },
  $(go.Panel, "Auto",
    $(go.Shape, "RoundedRectangle",  // the rectangular shape around the members
      {
        name: "BGSHAPE",
        fill: "#1a252f",
        stroke: "#F1F1F1",
        strokeWidth: 2,
        alignment: go.Spot.Center,
        minSize: CellSize,
        desiredSize: CellSize,
      }),
    $(go.Panel, "Vertical",  // the header
      {
        alignment: go.Spot.TopCenter,
        background: "#1a252f",
      },
      $(go.TextBlock,
        {
          textAlign: "center",
          font: "12pt sans-serif",
          maxSize: new go.Size(160, NaN),
          stroke: "white",
          margin: 6,
        },
        new go.Binding("text", "key")
      ),
      $(go.Picture,
        { desiredSize: new go.Size(50, 50), margin: 8 },
        new go.Binding("source", "callTypeDialCode", imgTypeConverter),
        new go.Binding("visible", "callTypeDialCode", (nat) => nat !== undefined)
      ),
    ),  // end GROUP HEADER Panel 
    $(go.Panel, "Auto",
      {
        alignment: go.Spot.BottomCenter,
      },

      $(go.Shape,  // represents the area for all member parts
        {
          fill: "#313d4a",
          stroke: "transparent",
          minSize: new go.Size(120, 100),
          name: "EMPTY_SLOT",
          visible: true,
          alignment: go.Spot.BottomCenter,
        },
      ), // END NODE Panel
      // new go.Placeholder({ padding: 5 }), //IS the main to combine the nodes using node template

      $(go.Shape, // Transparent shape instead of placeholder
        {
          name: "PLACEHOLDER",
          fill: "transparent",
          stroke: "transparent",
          desiredSize: new go.Size(95, 95),
          alignment: go.Spot.BottomCenter,
          alignmentFocus: go.Spot.BottomCenter
        },
        new go.Binding("category", "", (data) => data.category === "occupied" ? "occupied" : ""),
      ),
    ),
    new go.Binding("category", "", (data) => data.category === "bgGroup" ? "bgGroup" : ""),
  ), // END AUTO Panel
  {
    toolTip: $(
      "ToolTip",
      { "Border.stroke": "#5b5b5b", "Border.strokeWidth": 2 },
      $(
        go.TextBlock,
        { margin: 8, stroke: "#5b5b5b", font: "bold 16px sans-serif" },
        new go.Binding("text", "key"),
      )
    ),
  }
);
dia.nodeTemplate = $(go.Node,
  "Vertical",
  {
    locationObjectName: 'RADIOS',
    locationSpot: go.Spot.BottomCenter,
    resizable: false,
    movable: true,
    category: "occupied",
  },
  new go.Binding("text", "key"), //for sorting 
  // new go.Binding("category", "", (data) => data.category === "occupied" ? "occupied" : ""),

  $(go.Panel, "Vertical", { name: 'ICON' },

    $(go.Picture, // flag image, only visible if a nation is specified
      {
        visible: false, desiredSize: new go.Size(50, 50), margin: 10, alignment: go.Spot.Bottom, alignmentFocus: go.Spot.BottomCenter,
      },
      new go.Binding("source", "callTypeDialCode", imgTypeConverter),
      new go.Binding("visible", "callTypeDialCode", (nat) => nat !== undefined),
      new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
    ),
    $(
      go.TextBlock,
      {
        alignment: go.Spot.BottomCenter,
        alignmentFocus: go.Spot.BottomCenter,
        margin: 2,
        maxSize: new go.Size(160, NaN),
        font: "12pt sans-serif",
        stroke: "white",
      },
      new go.Binding("text", "key"),
    ),
  ),
  {
    toolTip: $(
      "ToolTip",
      { "Border.stroke": "#5b5b5b", "Border.strokeWidth": 2 },
      $(
        go.TextBlock,
        { margin: 8, stroke: "#5b5b5b", font: "bold 16px sans-serif" },

        new go.Binding("text", "key"),
      )
    ),
  }
)  //END of Diagram NODE Template
return dia;

}

Blockquote

Could you please provide us with a screenshot of what you have and what it is that you’re trying to achieve?

Also, it would help if you formatted your code properly.

Alignment_Error_

this is using grid layout and placeholder to hold the node template part…

Below is using Kanban board pool layout, where the movement of node without group is not achieved due to some reason of converting the node template to my angular format… And further need to select the group in order to assign my node properly… In Kanban board sample group is not allowed to select and interact…
Alignment_Expected_

initDiagram(): go.Diagram {
    const $ = go.GraphObject.make;
    let dia = $(go.Diagram, {
      "undoManager.isEnabled": true,
      "animationManager.isEnabled": true,
      "allowVerticalScroll": false,
      "allowHorizontalScroll": false,
      "allowDelete": false,
      "allowCopy": false,
      "allowClipboard": false,
      "allowInsert": false,
      layout: $(go.GridLayout,
        {
          spacing: new go.Size(25, 25),
          wrappingColumn: 5,
        }),
      mouseDrop: (e) => {
        e.diagram.currentTool.doCancel();
      },
      model: new go.GraphLinksModel(
        {
          nodeKeyProperty: 'key',
          linkKeyProperty: 'key', 
          nodeCategoryProperty: "category"
        }),
    });
    dia.commandHandler.archetypeGroupData = { key: 'Group', isGroup: true };
    const CellSize = new go.Size(130, 200);
    dia.toolManager.draggingTool.doActivate = function () {
      let part = this.diagram.selection.first(); 
      if (part instanceof go.Node || part.name === "PLACEHOLDER") {
        go.DraggingTool.prototype.doActivate.call(this);
      } else {       
        this.diagram.currentTool.doCancel();
      }
    };
  
    dia.addDiagramListener("SelectionMoved", (e) => {
      e.subject.each((part) => {
        if (part instanceof go.Node) {
          const node = part as go.Node;
          const newGroup = node.containingGroup;
          if (newGroup) {
            console.log("Node moved to group:", newGroup.data.key);
           
          } else {
            console.log("Node is not inside any group");
          }
        }
      });
    });

    dia.groupTemplate = $(go.Group, "Vertical",
      {
        locationObjectName: 'GROUP',
        movable: false,
        background: "transparent",
        layerName: "bgGroup",
        category: "bgGroup",
        locationSpot: go.Spot.Center,
        padding: 5,
        layout: $(go.GridLayout, {
          wrappingColumn: 1,
        }),
        mouseDrop: (e, grp) => {
          if (grp instanceof go.Group && e.diagram.selection.all((n) => !(n instanceof go.Group))) {
            const ok = grp.addMembers(grp.diagram.selection, true);
            if (!ok) grp.diagram.currentTool.doCancel();
          }
        },
        click: (e, obj) => {
          obj.part.isHighlighted = true,
            console.log('obj key is ', obj.part.data.key)
        }
      },
      $(go.Panel, "Auto",
        $(go.Shape, "RoundedRectangle",
          {
            name: "BGSHAPE",
            fill: "#1a252f",
            stroke: "#F1F1F1",
            strokeWidth: 2,
            alignment: go.Spot.Center,
            minSize: CellSize,
            desiredSize: CellSize,
          }),
        $(go.Panel, "Vertical",
          {
            alignment: go.Spot.TopCenter,
            background: "#1a252f",
          },
          $(go.TextBlock,
            {
              textAlign: "center",
              font: "12pt sans-serif",
              maxSize: new go.Size(160, NaN),
              stroke: "white",
              margin: 6,
            },
            new go.Binding("text", "key")
          ),
          $(go.Picture,
            { desiredSize: new go.Size(50, 50), margin: 8 },
            new go.Binding("source", "callTypeDialCode", imgTypeConverter),
            new go.Binding("visible", "callTypeDialCode", (nat) => nat !== undefined)
          ),
        ), 
		
        $(go.Panel, "Auto",
          {
            alignment: go.Spot.BottomCenter,
          },

          $(go.Shape,  
            {
              fill: "#313d4a",
              stroke: "transparent",
              minSize: new go.Size(120, 100),
              name: "EMPTY_SLOT",
              visible: true,
              alignment: go.Spot.BottomCenter,
            },
          ),
         
          $(go.Shape, // Transparent shape instead of placeholder
            {
              name: "PLACEHOLDER",
              fill: "transparent",
              stroke: "transparent",
              desiredSize: new go.Size(95, 95),
              alignment: go.Spot.BottomCenter,
              alignmentFocus: go.Spot.BottomCenter
            },
            new go.Binding("category", "", (data) => data.category === "occupied" ? "occupied" : ""),
          ),
        ),
        new go.Binding("category", "", (data) => data.category === "bgGroup" ? "bgGroup" : ""),
      ), 
      {
        toolTip: $(
          "ToolTip",
          { "Border.stroke": "#5b5b5b", "Border.strokeWidth": 2 },
          $(
            go.TextBlock,
            { margin: 8, stroke: "#5b5b5b", font: "bold 16px sans-serif" },
            new go.Binding("text", "key"),
          )
        ),
      }
    );
    dia.nodeTemplate = $(go.Node,
      "Vertical",
      {
        locationObjectName: 'RADIOS',
        locationSpot: go.Spot.BottomCenter,
        resizable: false,
        movable: true,
        category: "occupied",
      },
      new go.Binding("text", "key"), 
      $(go.Panel, "Vertical", { name: 'ICON' },

        $(go.Picture,
          {
            visible: false, desiredSize: new go.Size(50, 50), margin: 10, alignment: go.Spot.Bottom, alignmentFocus: go.Spot.BottomCenter,
          },
          new go.Binding("source", "callTypeDialCode", imgTypeConverter),
          new go.Binding("visible", "callTypeDialCode", (nat) => nat !== undefined),
          new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
        ),
        $(
          go.TextBlock,
          {
            alignment: go.Spot.BottomCenter,
            alignmentFocus: go.Spot.BottomCenter,
            margin: 2,
            maxSize: new go.Size(160, NaN),
            font: "12pt sans-serif",
            stroke: "white",
          },
          new go.Binding("text", "key"),
        ),
      ),
      {
        toolTip: $(
          "ToolTip",
          { "Border.stroke": "#5b5b5b", "Border.strokeWidth": 2 },
          $(
            go.TextBlock,
            { margin: 8, stroke: "#5b5b5b", font: "bold 16px sans-serif" },

            new go.Binding("text", "key"),
          )
        ),
      }
    )  
    return dia;
  }

How is what you want to do different from the behavior in the Regrouping sample? Regrouping Editor for Dragging Nodes into and out of Groups | GoJS Diagramming Library

Clearly the groups and nodes will have a different appearance, but that should not matter for this discussion.

Difference is moving only Node and not the whole group with node as regrouping sample, As told earlier and shared screen shot kanban board editor, should allow to reassign to different groups without moving the group itself… Interactive Kanban Board Diagram Using Collapsible Groups as Task Lists | GoJS Diagramming Library

Have you set Group.computesBoundsAfterDrag to true? Group | GoJS API

From the Kanban sample:

computesBoundsAfterDrag: true, // needed to prevent recomputing Group.placeholder bounds too soon

yes it is added, overcame it by assigning a dummy transparent shape to fill up the (first half of group) node template, where node and group center alignment is originating at same space, am not sure why this happens…