How to horizontally stretch TextBlock inside table column

Hello everyone! For you guys it’s probably a simple thing: I want to have an editable TextBlock inside a table column to stretch the whole width of the column.

           $(go.Panel, "Table",
              {
                row: 4,
                name: "Attributes",
                alignment: go.Spot.TopLeft,
                defaultAlignment: go.Spot.Left,
                defaultRowSeparatorStroke: "#f0f0f0",
                stretch: go.GraphObject.Horizontal,
                margin: 5,
                itemTemplate: $(go.Panel, "TableRow",
                  $(go.TextBlock,
                    {
                      column: 0,
                      stroke: "#7a7a7a",
                      height: 24,
                      width: 24,
                      verticalAlignment: go.Spot.LeftCenter,
                      spacingAbove: 4.2
                    },
                    new go.Binding("text", "icon").makeTwoWay()
                  ),
                  $(go.TextBlock,
                    {
                      column: 1,
                      name: "EditAttributeBlock",
                      stroke: "#333333",
                      height: 24,
                      editable: true,
                      isMultiline: false,
                      verticalAlignment: go.Spot.LeftCenter,
                      stretch: go.GraphObject.Horizontal
                    },
                    new go.Binding("text", "label").makeTwoWay()
                  )
                )
              },
              new go.Binding("itemArray", "attributes"),

Now my issue is that when I set the stretch on the TextBlock in column 1, then the table gets ‘oversized’. Since the column 1’s width computes to 100% of the available width and column 0 and column 2 have a fixed width of 30px, the table ends up being 100% of the container width + 60px.

How do I make it fit into the available width as an HTML table would do? Thank you!

I don’t see a column 2, and each TextBlock in column 0 has a width of 24.

But if the whole “Table” Panel is wider than needed for 24 + the widest text in column 1, then extra space is given proportionally to each column, just as in HTML. You can disable that by setting RowColumnDefinition.sizing to go.RowColumnDefinition.None on either or both columns.

Hi walter! Sorry I forgot to add the lines containing the row definitions:

              ...
              new go.Binding("itemArray", "attributes"),
              $(go.RowColumnDefinition, { column: 0, width: 30 }),
              $(go.RowColumnDefinition, { column: 1 }),
              $(go.RowColumnDefinition, { column: 2, width: 30 }),

The text in column 1 will be 100% of the initial table size because I have stretch: go.GraphObject.Horizontal set on it. At least that is how it behaves for me.

I will try your suggestion and see what happens. :-) Thank you!

This is how it looks:

Sorry, but I cannot tell what is what.

The “Table” Panel itself stretches horizontally. What width is it getting?

Sorry for the confusion, Walter. I hope this helps:

I do not want the table to extend itself to the left and the right. But I want the textblock in the middle cloumn to span the whole available width so that it is easier to hit with the mouse for editing.

So the “EditAttributeBlock” has the value “id”?

I still do not know what is what. There is no Picture in your quoted “Table” Panel. And there us no blue “Circle” Shape.

What arrangement do you want instead?

This is what it looks like when I remove the stretch: go.GraphObject.Horizontal from the TextBlock in column 1 of the atttributes table.

Close, but no cigar. This is what it should look like:

With the textbox in column 1 spanning the whole width so that its easier to hit it with the mouse when the text is short.

And here’s the whole node template:

this.diagram.nodeTemplate =
      $(go.Node, 'Vertical',
        {
          minSize: new go.Size(100, 0),
          isShadowed: true,
          shadowOffset: new go.Point(2, 2),
          shadowColor: "#ccc",
          selectionObjectName: "Shape",
          fromSpot: go.Spot.AllSides,
          toSpot: go.Spot.AllSides,
          isTreeExpanded: false,
          selectionChanged: (node) => {
            this._store.dispatch(SelectResourceAction({ uri: node.data.id }));
          }
        },
        new go.Binding("location", "location").makeTwoWay(),
        new go.Binding("isTreeLeaf", "hasSubClasses", v => !v),
        $(go.Panel, 'Auto',
          $(go.Shape, 'RoundedRectangle',
            { name: "Shape", stroke: '#e0e0e0', fill: '#fff' }
          ),
          $(go.Panel, "Table",
            { stretch: go.GraphObject.Fill },
            $(go.RowColumnDefinition,
              { row: 0, sizing: go.RowColumnDefinition.None }
            ),
            $(go.Panel, "Vertical",
              {
                row: 1,
                itemTemplate:
                  $(go.Panel, "Horizontal",
                    $(go.Picture,
                      {
                        height: 75, background: "chartreuse",
                        imageStretch: go.GraphObject.UniformToFill
                      },
                      new go.Binding("source", "url")
                    )
                  )
              },
              new go.Binding("itemArray", "images")
            ),
            $(go.Panel, "Horizontal",
              {
                row: 2,
                margin: 5
              },
              $(go.Shape,
                {
                  figure: "Circle",
                  desiredSize: new go.Size(14, 14),
                  stroke: null,
                  margin: 5
                },
                new go.Binding("fill", "color")),
              $(go.TextBlock,
                {
                  name: "ClassNameBlock",
                  editable: true,
                  alignment: go.Spot.Center
                },
                new go.Binding("text", "label").makeTwoWay())
            ),
            $(go.Panel, "Table",
              {
                row: 4,
                name: "Attributes",
                alignment: go.Spot.TopLeft,
                defaultAlignment: go.Spot.Left,
                defaultRowSeparatorStroke: "#f0f0f0",
                stretch: go.GraphObject.Horizontal,
                margin: 5,
                itemTemplate: $(go.Panel, "TableRow",
                  $(go.TextBlock,
                    {
                      column: 0,
                      font: "20px 'XSD Icons'",
                      stroke: "#7a7a7a",
                      height: 24,
                      width: 24,
                      verticalAlignment: go.Spot.LeftCenter,
                      spacingAbove: 4.2,
                      // Todo: Add editing behavior
                    },
                    new go.Binding("text", "icon").makeTwoWay()
                  ),
                  $(go.TextBlock,
                    {
                      column: 1,
                      name: "EditAttributeBlock",
                      stroke: "#333333",
                      height: 24,
                      editable: true,
                      isMultiline: false,
                      verticalAlignment: go.Spot.LeftCenter,
                      //stretch: go.GraphObject.Horizontal,
                      // Todo: Add hover behavior
                    },
                    new go.Binding("text", "label").makeTwoWay(),
                  ),
                  $("Button",
                    {
                      column: 3,
                      margin: 2,
                      width: 20,
                      click: (e, obj) => {
                        const classUri = obj.part.data.id;
                        const propertyUri = obj.part.data.attributes[obj.row]?.id;

                        // Todo: Implement attribute removal business logic.
                        console.warn(classUri, propertyUri);

                        this.diagram.model.removeArrayItem(obj.part.data.attributes, obj.row);
                      }
                    },
                    $(go.TextBlock, {
                      font: "bold 14px 'Material Icons'",
                      text: "",
                      stroke: '#424242',
                      height: 14,
                      width: 14,
                      verticalAlignment: go.Spot.Center,
                      spacingAbove: 1.3
                    })
                  ),
                )
              },
              new go.Binding("itemArray", "attributes"),
              // Note: The stretching behavior of the table is a bit weird. It will compute the required size
              // for all children in the row and the sum of these values is the table width. Because we have 
              // one clumn that will stretch horizontally, the resulting table size is 100% (available space) 
              // + 2 * 30px. That means the table will use up 60px more horizontal size than given by the 
              // container. To fix this, we add a padding to the stretched column and move all adjacent columns 
              // into that column via a negative padding. Hacky, but it works.
              $(go.RowColumnDefinition, { column: 0, width: 30 }),
              $(go.RowColumnDefinition, { column: 1 }),
              $(go.RowColumnDefinition, { column: 2, width: 30 }),
            )
          ),
        ),
        $("TreeExpanderButton",
          {
            name: 'InsertSubClassButton',
            width: 20,
            height: 20,
            alignment: go.Spot.BottomCenter,
            alignmentFocus: go.Spot.Center,
            click: (e, button) => {
              const node = button.part;

              if (node != null) {
                e.handled = true;

                this.insertSubClassNodes(node);
              }
            }
          },
          new go.Binding("visible", "info.hasSubClasses")
        )
      );

Hmmm, we’re investigating this. In the meantime…

Ah, so there’s a “Table” Panel surrounding the “Table” Panel. Looking at that and the whole template, I hope you don’t mind if I provide some comments.

  • You might want to put the minimum width (minSize: new go.Size(100, 0)) on the “Auto” Panel, since I assume that’s the width you want to control; alternatively you could stretch the “Auto” Panel horizontally.
  • There is a RowColumnDefinition for sizing row 0, yet there’s nothing in row 0
  • There is nothing in row 3 either, but that’s OK – it has no effect
  • Did you want the images in row 1 to be above each other vertically or next to each other horizontally? They are currently arranged vertically due to the “Vertical” type of Panel. The “Horizontal” declaration for the item Panel has no effect because there is only a single element in that panel – the Picture.
  • In the nested “Table” you have the Button in column 3 but you specify the width of column 2 to be 30. There’s nothing in column 2 but it will have a width of 30. Did you mean to just provide either adjacent element a margin?

Thank you for your patience in reproducing this for us. This has been fixed and will be out with the next release, probably within a week or so.

Thank you guys for looking into this. Highly appreciated! :-)

Hello @faubulous, we’ve just released GoJS 2.2.7, which should fix this Table panel issue.