Creating a new group on HTML button click

Hi, I am a noob here. I am trying to add a new group without any nodes inside. but so far no success. Kindly guide me to the right direction.
what I actually want to do is that…
I have a HTML button, and “onclick” it will ask user to enter groupName and groupText. and then on user confirmation, it should add an empty group to the diagram.

I have tried doing it like this…but it doesn’t change anything

var nodeObj = {key: "newKey", text: $("#inputText").val(), name: $("#inputName").val(), isGroup: true};
myDiagram.startTransaction("newGroup");
myDiagram.model.addNodeData(nodeObj);
myDiagram.commitTransaction("newGroup");

I have also tried to do it like this… but it messes up the links

var nodeObj = {key: "newKey", text: $("#inputText").val(), name: $("#inputName").val(), isGroup: true};
myDiagram.model = new go.GraphLinksModel(nodeObj);

I have noticed than when I do like this…

myDiagram.model.addNodeData(nodeObj);

then I can see the node added in console. but it doesn’t appear in the diagram, and diagram.redraw() also has no effect… need help!!!

Your first try is correct. But you did not specify a location for the group, so unless your Diagram.layout positioned it for you, the new group would not have any real location. You should never have to ask the diagram to update itself – ending a transaction will do that.

Your second attempt has a wrong argument to the constructor. If you are using the debug version of the library, I think you should have gotten an error message.

I have added location but still it is not showing the new group.
here is my code…

var _go = go.GraphObject.make;
myDiagram = _go(go.Diagram, "myDiagramDiv", 
 {
    grid: _go(go.Panel, "Grid",  {gridCellSize: new go.Size(10, 10)},
          _go(go.Shape, "LineH", {stroke: "#EAEAEA"}),
          _go(go.Shape, "LineV", {stroke: "#EAEAEA"})
          ),
    allowReshape: false,
    allowResize: false,
    allowRotate: false,
    hasHorizontalScrollbar: false,
    hasVerticalScrollbar: false,
    padding: 0,
    layout: _go(go.ForceDirectedLayout, {defaultSpringLength: 10}),
    initialAutoScale: go.Diagram.UniformToFill,
    autoScale: go.Diagram.Uniform,
    maxSelectionCount: 2,  

});

And then after the init(); I change some properties

setTimeout(function () {
     myDiagram.toolManager.mouseWheelBehavior = go.ToolManager.WheelZoom;
     myDiagram.layout.isOngoing = false; 
     myDiagram.defaultCursor = "grab";
     myDiagram.contentAlignment = go.Spot.Left;
     myDiagram.autoScale = go.Diagram.None;
}, 2500);

And following is the code for my group Template

 myDiagram.groupTemplate = _go(go.Group, "Auto",
     {
         background: "rgba(51, 122, 183, 0.1)",
         ungroupable: true,
         computesBoundsAfterDrag: true,
         handlesDragDropForMembers: true, 
         layout: _go(go.GridLayout, {
                     wrappingColumn: 3, 
                     alignment: go.GridLayout.Position,
                     cellSize: new go.Size(1, 1), 
                     spacing: new go.Size(10, 30)
          })
     },
     _go(go.Shape, "Rectangle", {
                               fill: null, 
                               stroke: "#337AB7", 
                               strokeWidth: 2
                               }),
     _go(go.Panel, "Vertical", // title above Placeholder
     _go(go.Panel, "Horizontal", {
                              stretch: go.GraphObject.Horizontal, 
                              background: "#337AB7"
                               },
     _go("Button", {
            "_expandedFigure": img_colaspe,
            "_collapsedFigure": img_expand,
            "_expandedFigureSize": new go.Size(15, 15),
            "_collapsedFigureSize": new go.Size(15, 15),
            click: expandGroup, //to expand or collapse the groups on button click
            padding: 5
          },
          go.GraphObject.make(go.Picture, {
               maxSize: new go.Size(15, 15),
               source: img_colaspe
          },
           new go.Binding("source", "isSubGraphExpanded", function (exp, shape) {
                  var button = shape.panel;
                  return exp ? button["_expandedFigure"] : button["_collapsedFigure"];
            }).ofObject(),
            new go.Binding("maxSize", "isSubGraphExpanded", function (exp, shape) {
                  var button = shape.panel;
                  return exp ? button["_expandedFigureSize"] : button["_collapsedFigureSize"];
            }).ofObject()
         )
   ), // end button
  _go(go.TextBlock,  {
            name: "GROUPTEXT",
            alignment: go.Spot.TopLeft,
            margin: 7,
            font: "Bold 14px Sans-Serif",
            stroke: "white"
          },
          new go.Binding("text", "name"))
         ), // end Horizontal Panel
          _go(go.Placeholder,  {padding: 25, alignment: go.Spot.TopLeft})
       ), // end Vertical Panel
       new go.Binding("collaspeAll", "", colaspeGroupOnload)
 );

expandGroup(); is called on click to expand the collapsed group
colaspeGroupOnload(); is called to collapse a group by default

Create new group Button code (Now with loc parameter)

$("#btn_create").click(function () {
     var nodeObj = {key: "new", text: $("#inputName").val(), name: $("#inputName").val(), isGroup: true, loc: "0 0"};
     myDiagram.startTransaction("newGroup");
     myDiagram.model.addNodeData(nodeObj);
     myDiagram.commitTransaction("newGroup");
     setTimeout(function () {
          $("#zoneModal").modal('hide');
          $("#btn_save").removeClass("disabled");
      }, 200);
  });

Do i need to use myDiagram.groupTemplateMap.add(..) ?? I cant figure out the reason of new group not showing…

I have found out that if I comment out this code
myDiagram.layout.isOngoing = false;
then new group can be created successfully. but adding new group slightly changes the layout… and updating links changes the layout completely, which is not good in this scenario. so is their a way to create a group by still keeping isOngoing = false

and now that i am able to create new group by keeping isOngoing to true, but loc is not showing any effect… nodes and groups created on page load are on left, but i want the newly created node to appear on the right side of the screen. but it is appearing on random locations each time. is it due to using ForceDirectedLayout??

I’m having a hard time understand your code. I’m not sure I can answer your specific question, so I’ll provide some comments.

First, I should remind everyone that during development they should be using the debug library (go-debug.js) and checking the console window for warning or error messages.

Regarding the Diagram initializations:

  • those three allowRe... properties default to true, but unless you have nodes that set or bind Part.reshapable, Part.resizable, or Part.rotatable to true, the user will not be able to do any of those three operations.
  • the value of Diagram.autoScale will supercede the value of Diagram.initialAutoScale

There is no need to do the other initializations inside the setTimeout – in fact that might be disconcerting to users when things change suddenly without any actions on their part. The exception is setting Diagram.autoScale back to None, which would be better done in a “InitialLayoutCompleted” DiagramEvent listener.

So it turns out that you do have a Diagram.layout, but you have set Layout.isOngoing to false, which means the layout will not be invalidated as nodes or links are added or removed. That means you do need to assign or bind the Group.location, because the layout won’t do it for you. Well, if you add the group after 2.5 seconds. Before then the layout will move the group. This is why changing things after 2.5 seconds is not a good idea.

I don’t see the point of setting “_expandedFigureSize” and binding Picture.maxSize when you have already set it to the same Size.

I don’t know what expandGroup does, but I hope it is similar to what the click handler in the “SubGraphExpanderButton” does, as shown in http://gojs.net/latest/extensions/Buttons.js.

There is no “Group.collaspeAll” property, so that last Binding won’t work.

Are you sure that you want to call $("#btn_save").removeClass("disabled") after the “btn_create” click event? I think it would be more general to enable the save button when the diagram’s model has been modified, not only after the user has added a group. Many of the samples do this.

thanks for the detailed reply. all instructions are much appreciated. I have corrected all the mistakes, but I am still not able set the location of groups.

The 2.5 second is a rough timeout just to make sure that the diagram is ready with all nodes on it.(server takes almost 2 seconds to send data). I told you earlier that user can create group at anytime by creating new group button… so It is required to add group after InitialLayoutCompleted

_expandedFigureSize and Picture.maxSize are not being used currently, but i will use them later to improve the UI of the group.

and yes expandGroup is same as SubGraphExpanderButton. the only reason to do it manually was to customize the button.

about Group.collaspeAll… I know there is no such property but strangely if we bind with any random name without any event in it. it works… it doesn’t actually works on collapsing groups, it works only once as the group is created. The code inside colaspeGroupOnload collapses expanded group. because the parameters for colaspeGroupOnload have group object. so I was able to achieve the requirement. it was not giving any warning or error, so I thought to continue doing it like this

function colaspeGroupOnload(e, obj) {
      var group = obj.part;
      var diagram = group.diagram;
      var cmd = diagram.commandHandler;
      cmd.collapseSubGraph(group);
      addGroupIcon(group);
}

addGroupIcon for adding an icon inside a collapsed group

 function addGroupIcon(group) {
        group.add(go.GraphObject.make(go.Picture, {
           maxSize: new go.Size(45, 45),
           source: img_group,
           alignment: new go.Spot(0.5, 0.9)
        }));
  }

Please correct me, as i don’t know any other way for doing this.

and about $("#btn_save").removeClass("disabled") yes this is right. as their are three buttons… first one $("#btn_openNew") opens the bootstrap modal asking user to enter group name and text, and also has the $("#btn_create") which will create the group in diagram, but will not save it. hence the 3rd button $("#btn_save") will save the added or modified groups.

If you debug how often your colaspeGroupOnload function is called, you will see that what you are doing is not the best way.

yes you are right, i have changed it now like this…

new go.Binding("isSubGraphExpanded", "", colaspeGroupOnload)

function colaspeGroupOnload(e, obj) {
        addGroupIcon(obj.part);
        return false; // to colaspe the group
}

Now there is no warring or error, but is it the right way of doing it now??
I think it would be better if i could collapse all the groups after init() in a setTimeout function. but I can not find the groups in myDiagram object…!!! Can you guide me that how can I access groups in myDiagram object?

and I am also able to set the location of group by setting Group.location so Thanks a lot for helping, I have learned so much :)

Performing side-effects in conversion functions is still a bad idea. (Other than setting the target property, of course.)

In this case you still do not know how often or when your addGroupIcon function will be called. Try putting in an alert and you will see how many copies of the Picture are added as the app is used. But I do not understand when you want that group icon to be added. Why isn’t it there as part of the template? You can toggle its visible property if you want to show or hide it at different times.

Regarding that other issue, just make sure that Group.isSubGraphExpanded is set to false, if you want the group to start off collapsed.