MouseOver Adornments Stop Working After Model Switch


My diagram represents a few different data models. I’m using a set of custom adornment buttons that show on mouseOver of nodes. All that works perfectly… up until I switch the data model for the diagram. From there, the Adornments stop working. The function to add them is still firing - but it’s not actually adding the adornments.

My codebase is getting large enough that I wasn’t sure it wasn’t just something else I was doing. So I made a issue-recreation out of the “Minimal” sample.

Modified “Minimal”

<!DOCTYPE html>
  <meta charset="UTF-8">
  <title>Minimal GoJS Sample</title>
  <meta name="description" content="An almost minimal diagram using a very simple node template and the default link template." />
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- Copyright 1998-2020 by Northwoods Software Corporation. -->

  <script src="../GoJS/release/go.js"></script>
  <script src="../GoJS/assets/js/goSamples.js"></script>  <!-- this is only for the GoJS Samples framework -->
  <script id="code">
    function init() {
      // if (window.goSamples) goSamples();  // init for these samples -- you don't need to call this

      var $ = go.GraphObject.make;  // for conciseness in defining templates

      myDiagram = $(go.Diagram, "myDiagramDiv",  // create a Diagram for the DIV HTML element
          "undoManager.isEnabled": true  // enable undo & redo

      // define a simple Node template
      myDiagram.nodeTemplate =
        $(go.Node, "Auto",  // the Shape will go around the TextBlock
          $(go.Shape, "RoundedRectangle", { strokeWidth: 0, fill: "white",
            mouseOver: function(e, obj) { //that was easy.
            console.log("Still fires after model change");
            var node = obj.part;
            customButtons.adornedObject = node;
            node.addAdornment("mouseHover", customButtons); //works until the "changeModel" function runs, then no longer shows adornments
            // Shape.fill is bound to
            new go.Binding("fill", "color")),
            { margin: 8, font: "bold 14px sans-serif", stroke: '#333' }, // Specify a margin to add some room around the text
            // TextBlock.text is bound to
            new go.Binding("text", "key"))

      // but use the default Link template, by not setting Diagram.linkTemplate

      var customButtons =
    $(go.Adornment, "Spot",
      $(go.Panel, "Horizontal",
        $(go.Placeholder)  // this represents the selected Node
      // the button to search the model (aka fill the palette)
          alignmentFocus: go.Spot.Right,
          alignment: go.Spot.Left,
          click: changeModel,  // this function is defined below
              $(go.TextBlock, {
                margin: 4,
                text: "Explore This Node"
        $(go.TextBlock, { text: 'adornment button' })
      )) // end button

      function changeModel(){
        myDiagram.model = new go.Model.fromJson(alternateModel);

      // create the model data that will be represented by Nodes and Links
      myDiagram.model = new go.GraphLinksModel(
          { key: "Alpha", color: "lightblue" },
          { key: "Beta", color: "orange" },
          { key: "Gamma", color: "lightgreen" },
          { key: "Delta", color: "pink" }
          { from: "Alpha", to: "Beta" },
          { from: "Alpha", to: "Gamma" },
          { from: "Beta", to: "Beta" },
          { from: "Gamma", to: "Delta" },
          { from: "Delta", to: "Alpha" }

      var alternateModel = {
        "class": "GraphLinksModel",
        "nodeDataArray": [
          { key: "Mario", color: "red" },
          { key: "Luigi", color: "green" },
          { key: "Peach", color: "pink" },
          { key: "Toad", color: "grey" }
        "linkDataArray": [
          { from: "Mario", to: "Luigi" },
          { from: "Peach", to: "Luigi" },
          { from: "Toad", to: "Luigi" },
          { from: "Peach", to: "Toad" },
          { from: "Mario", to: "Peach" }
<body onload="init()">
<div id="sample">
  <!-- The DIV for the Diagram needs an explicit size or else we won't see anything.
       This also adds a border to help see the edges of the viewport. -->
  <div id="myDiagramDiv" style="border: solid 1px black; width:400px; height:400px"></div>
    This isn't a truly <i>minimal</i> demonstration of <b>GoJS</b>,
    because we do specify a custom Node template, but it's pretty simple.
    The whole source for the sample is shown below if you click on the link.
    This sample sets the <a>Diagram.nodeTemplate</a>, with a <a>Node</a> template that data binds both the text string and the shape's fill color.
    For an overview of building your own templates and model data, see the <a href="../learn/index.html">Getting Started tutorial.</a>
    Using the mouse and common keyboard commands, you can pan, select, move, copy, delete, and undo/redo.
    On touch devices, use your finger to act as the mouse, and hold your finger stationary to bring up a context menu.
    The default context menu supports most of the standard commands that
    are enabled at that time for the selected object.
    For a more elaborate and capable sample, see the <a href="basic.html">Basic</a> sample.
    For a sample that loads JSON data from the server,
    see the <a href="minimalJSON.html">Minimal JSON</a> sample.
    For a sample that loads XML data from the server,
    see the <a href="minimalXML.html">Minimal XML</a> sample.

That code demonstrates the issue. Initially, the button with text ‘adornment button’ displays on mouse over. Upon clicking the button and switching to the alternateModel, the adornment button no longer displays on mouse over — but the console log in the calling function indicates it is still firing.

What am I missing here?

Thank you,

One problem is that you never remove the Adornment from any Node. If I change your code to be:

      function changeModel(){
        var node = customButtons.adornedPart;
        if (node) node.removeAdornment("mouseHover", customButtons);
        myDiagram.model = new go.Model.fromJson(alternateModel);

I think everything works as you expect.

I’m not sure why it seems to work before replacing the old nodes with new nodes for the new model. Just lucky, I guess.