Text not visible for panel with itemTemplate since goJS 3.0.17

I have a panel with an itemTemplate and itemArray defined. The panel is placed in a go.Spot Panel:

const panel = new go.Panel(go.Panel.Spot);
panel.itemTemplate = this.createDurationTextPanel();
panel.itemArray = segments;

The itemTemplate defined a Panel which is placed using go.Spot alignment:

private createDurationTextPanel() {
    const textPanel = new go.Panel();
    textPanel.bind(
        new go.Binding("alignment", "", (panel: go.Panel) => {
            return new go.Spot(0, 1, someCalculatedOffsetA, someCalculatedOffsetB);
        }).ofObject());
    const textBlock = new go.TextBlock().bind("text", "",
            (segment) => this.getDurationText(segment));
    textPanel.add(textBlock);
    return textPanel;
}

This worked fine until goJS 3.0.16:
grafik

It doesn’t work anymore since goJS 3.0.17 (also checked with latest 3.0.19):
The alignment binding works (I can see that if I add some static text to the TextBlock).
The text binding is evaluated and returns a value (verified through debugging), but the text are not displayed anymore:
grafik

Any ideas?

I don’t know. When I try this code, it seems to work OK.

myDiagram.nodeTemplate =
  new go.Node("Spot", {
      itemTemplate:
        new go.Panel("Vertical", { alignmentFocus: go.Spot.BottomLeft })
          .bind("alignment", "", d => new go.Spot(1, 1, d.x, d.v))
          .add(
            new go.TextBlock()
              .bind("text", "w", item => item.toString()),
            new go.Shape("LineH", { width: 10, height: 0 })
              .bind("width", "w")
          )
    })
    .bind("itemArray")
    .add(
      new go.Shape({ isPanelMain: true, width: 0, height: 0, strokeWidth: 0 })
    )

myDiagram.model = new go.GraphLinksModel(
[
  { key: 1, text: "Alpha", color: "lightblue",
    itemArray: [
      { x: 0, w: 23, v: 10 },
      { x: 23, w: 17, v: 20 },
      { x: 40, w: 45, v: 15 },
      { x: 85, w: 39, v: 5 }
    ]
   }
]);

Have you set Diagram.renderer?

Hello,

sorry for the delay. I was now able to create an example for this issue.

See demo here (change version in script tag to see difference):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>GoJS Spot Panel ItemArray Demo</title>
    <!-- Works -->
    <!-- <script src="https://unpkg.com/[email protected]/release/go.js"></script> -->
    <!-- Does not work -->
    <script src="https://unpkg.com/[email protected]/release/go.js"></script>

    <style>
      html,
      body {
        height: 100%;
        margin: 0;
        font-family: Arial, sans-serif;
        background: #f5f5f5;
      }

      #myDiagramDiv {
        width: 100%;
        height: 100vh;
        background: white;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
      }

      header {
        padding: 1rem;
        background: #2f4f4f;
        color: #ffffff;
        text-align: center;
      }

      main {
        height: calc(100vh - 70px);
        display: flex;
        justify-content: center;
        align-items: center;
        padding: 1rem;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>GoJS Spot Panel with itemArray</h1>
      <p>
        This demo adds parts directly to the diagram and uses a Spot Panel's
        itemTemplate to position TextBlocks.
      </p>
    </header>
    <main>
      <div id="myDiagramDiv"></div>
    </main>

    <script>
      (function () {
        const $ = go.GraphObject.make;

        const diagram = $(go.Diagram, "myDiagramDiv", {
          "undoManager.isEnabled": true,
        });

        const part = $(
          go.Part,
          "Spot",
          {
            location: new go.Point(0, 0),
            layerName: "Foreground",
          },
          $(go.Shape, "RoundedRectangle", {
            name: "SHAPE",
            fill: "#dae4e4",
            stroke: "#2f4f4f",
            strokeWidth: 2,
            width: 260,
            height: 180,
            spot1: go.Spot.TopLeft,
            spot2: go.Spot.BottomRight,
          })
        );

        part.itemTemplate = $(
          go.Panel,
          "Auto",
          new go.Binding("alignment", "alignment", go.Spot.parse),
          $(
            go.Shape,
            "RoundedRectangle",
            {
              fill: "#ffffff",
              stroke: "#2f4f4f",
              strokeWidth: 1,
              parameter1: 8,
              minSize: new go.Size(48, 24),
            },
            new go.Binding("fill", "fill"),
            new go.Binding("stroke", "stroke")
          ),
          $(
            go.TextBlock,
            {
              font: "bold 11pt sans-serif",
              margin: new go.Margin(4, 6, 4, 6),
              wrap: go.TextBlock.WrapFit,
              textAlign: "center",
            },
            new go.Binding("text", "text")
          )
        );

        part.itemArray = [
          { text: "Top Left", alignment: "0 0", fill: "#f9f9f9" },
          { text: "Top", alignment: "0.5 0", fill: "#fcf2d9" },
          { text: "Top Right", alignment: "1 0", fill: "#f9f9f9" },
          { text: "Left", alignment: "0 0.5", fill: "#d9f2fc" },
          {
            text: "Center",
            alignment: "0.5 0.5",
            fill: "#ffffff",
            stroke: "#1e88e5",
          },
          { text: "Right", alignment: "1 0.5", fill: "#d9f2fc" },
          { text: "Bottom Left", alignment: "0 1", fill: "#f9f9f9" },
          { text: "Bottom", alignment: "0.5 1", fill: "#fcf2d9" },
          { text: "Bottom Right", alignment: "1 1", fill: "#f9f9f9" },
        ];

        diagram.add(part);
      })();
    </script>
  </body>
</html>

Thanks – I can reproduce the difference in behavior, and we’ll investigate.

The problem is that the Part (a Node in this case) is not being created automatically from the model data, but programmatically being created and added to the Diagram. Alas, that can be done in a multitude of different ways. There wouldn’t be a problem if you weren’t depending on data binding.

It has always been the case that the proper order for data binding is that the Part is added to the Diagram, the Part.data property is set, and then bindings are evaluated. This is important to make sure that the binding environment be correctly set up. I guess it used to work sometimes in different orders, but that was coincidental. We made a change in 3.0.17 (and fixed in 3.0.18) so that bindings can be evaluated when there’s no Diagram.

That’s not the case here, where you are assigning Panel.data and then adding the Part to the Diagram. If you switch the order, it still works.

        // Add the Part to the Diagram before assigning any data
        diagram.add(part);

        part.itemArray = [
          . . .
        ];

        //diagram.add(part);

Another potential problem is that in this programmatic setup the itemTemplate hasn’t been “frozen” (an internal operation to optimize performance and prevent modifications to the template and its bindings), so there could be differences in binding behavior over time if the data or visual tree were modified. That’s not a problem in this case, but it would be better if you wanted to support such data binding that you specify a new go.Binding(“itemArray”) on the Node, call Panel.copyTemplate on that Node add a copy() of that to the Diagram, and then set the Node.data rather than just set Panel.itemArray. This is much more like what happens when you add a node data object to the model.