How to Add Link Label Text


I am trying to create a link label when the “ExternalObjectsDropped” listener is executed. I was able to create a link from a new node to another but unable to auto-generate the text label on the link.

The code below shows how I am creating the link on ExternalObjectsDropped.


      //diagram listener when a Tag is drop on pane;
      myDiagram.addDiagramListener("ExternalObjectsDropped", function(e) {
        var newnode = JSON.parse(myDiagram.model.toJson());
          key = newnode["nodeDataArray"][i]["key"]

        //check if a datasource tag.
        var size = newnode['nodeDataArray'].length;
        if(newnode['nodeDataArray'][size-1]['text'] == 'Datasource'){
          myDiagram.startTransaction("add node and link");
          newlink = { from: newnode['nodeDataArray'][size-1]['key'], to: 0, text:"hangup" };
          myDiagram.model.addLabelKeyForLinkData(newlink, newnode['nodeDataArray'][size-1]['key'])
            openModalWindow('Datasource', newnode['nodeDataArray'][size-1]);
        if(newnode['nodeDataArray'][size-1]['text'] == 'Play'){
          openModalWindow('Play', newnode['nodeDataArray'][size-1]);
        // do something with newnode

Since you posted some code here, I hope you don’t mind getting some commentary on it. I’ll go line-by-line.

        var newnode = JSON.parse(myDiagram.model.toJson());

This writes out the current diagram’s model as a text string (in JSON format) and then reads the whole thing back in. Basically you are making a copy of all of the model properties including the model data. This is extremely wasteful of time and space. Furthermore it could cause problems because you will be dealing with copies of the node data, not with the actual node data objects.

“newnode” is also a misleading name – it’s really the whole model’s state that has been copied, not just a single node.

          key = newnode["nodeDataArray"][i]["key"]

This iterates over all of the copied information’s array of copied node data objects, and sets the key global variable repeatedly. It would be much more efficient to do something like:

        var size = newmodel.nodeDataArray.length;
        var key = newmodel.nodeDataArray[size-1].key;

But you don’t make use of key in the rest of the listener, so it would be most efficient to just delete all of that code.

          myDiagram.startTransaction("add node and link");

The documentation for the “ExternalObjectsDropped” DiagramEvent says that the listener is called within a transaction, so you don’t need to call startTransaction. There’s no harm in doing so, except that you are calling it without making sure to call a corresponding commitTransaction or rollbackTransaction.

          newlink = { from: newnode['nodeDataArray'][size-1]['key'], to: 0, text:"hangup" };

It’s a bit unsafe to create a new link that always goes to the node whose key is zero, but I suppose that might be OK in your scenario.

        myDiagram.model.addLabelKeyForLinkData(newlink, newnode['nodeDataArray'][size-1]['key']);

I’m not sure what you are trying to accomplish here. It is highly unusual and somewhat problematic to have a link going from a node to somewhere and also have that same node be a label node on that link. Users cannot draw such a link interactively because the LinkingTool disallows it. You can certainly create such a link programmatically. However if you succeeded, you would probably get undesirable behavior.

As it so happens, unless you have set GraphLinksModel.linkLabelKeysProperty to be the name of some data property, the call to GraphLinksModel.addLabelKeyForLinkData will not succeed.

But do you really want to use the moderately obscure feature of having nodes be labels on links? Or do you just want to show some information on a link? If it’s the latter case, you’ll want to just add the label to your link template, and you don’t need to use nodes as labels at all.

Although I cannot be sure exactly what you want to do, I suggest that you add a label to your link template. At a minimum:

    myDiagram.linkTemplate =
          $(go.TextBlock, new go.Binding("text"))

Then the following code should be equivalent to what you had written:

myDiagram.addDiagramListener("ExternalObjectsDropped", function(e) {
    var newdata = e.diagram.selection.first().data;
    if (newdata.text === 'Datasource') {
        var newlink = { from: newdata.key, to: 0, text: "hangup" };
        openModalWindow(newdata.text, newdata);
    } else if (newdata.text === 'Play') {
        openModalWindow(newdata.text, newdata);

I hope these detailed comments will help you use GoJS more effectively.

Hi Walter,

Thanks for the detailed response and I don’t mind the line by line critique. I am working on creating an IVR call flow diagram that will generate a certain XML code to power IVR application hence the reason we need every new node to always go to a default node (hangup). So when a user drags a new node like Play File to the canvas, it should always go to a Hangup by default. We want every action to hangup so the phone call does not go on forever.

I do have linkTemplate created in my code. When I manually create a link from a “Diamond” node, it does create the link label but when I try creating the event it would not add the label.


Your scenario about always linking to the “hangup” node makes sense. The danger is that that node might not exist in the model or that it does exist but has a different key. But it could work.

If you copied the template from the Flow Chart sample, be aware that the template always has a textual label, but that it is not usually visible.

. . .
$(go.Panel, "Auto",  // the link label, normally not visible
      { visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5},
      new go.Binding("visible", "visible").makeTwoWay(),
. . .

Note how GraphObject.visible is set to false by default, so it requires a data.visible property set to true to cause it to appear.

In your case you might not want that default behavior.