itemTemplate PanelExpanderButton and binding

Hi,

I am trying GoJS to see if it can be usefull in a project.

I can’t find a way to dynamicaly generate the “text” property of a “PanelExpanderButton” so that it will be linked to a Panel “name” also dynamically generate. The value “tube_id” is unique.

Here is a part of the model:

            itemTemplate:
                GOJS(go.Panel, "Table",{ column: 0 },
                    GOJS(go.TextBlock, new go.Binding("text", "tube"),{column: 0,margin: 4}),
                    GOJS("PanelExpanderButton", new go.Binding("text", "tube_id"),{column: 1}),
                    GOJS(go.Panel, "Vertical",new go.Binding("name", "tube_id"),{
                        padding: 2,
                        itemTemplate: fieldTemplate,
                        row : 1,
                        column: 0,
                        columnSpan: 2
                    },
                    new go.Binding("itemArray", "fibers"))
                )

Here are the message that I got from the console:

Binding error: missing GraphObject named COLLAPSIBLE in Panel(Panel.Table)#19161
Binding error: cannot modify GraphObject.name on Panel(Panel.Vertical)#19168
Binding error: undefined target property: text on Panel(Panel.Auto)#19260

Any ideas ?

Thank you

The “PanelExpanderButton” Panel is a Panel, which does not have a text property, so trying to bind that property does not make sense. That’s why you are getting the last error message.

The “PanelExpanderButton”, whose definition you can read in the extensions/Buttons.js file, is looking for a GraphObject whose name is “COLLAPSIBLE”. When the user clicks the button it will show or hide that named GraphObject. That explains the first error message.

To avoid confusion, one cannot modify at runtime the value of GraphObject.name, neither by setting nor by binding.

What is it that you want the “PanelExpanderButton” to expand/collapse? Just give it a name: "COLLAPSIBLE". There are a number of examples of this throughout the samples.

I was following this documentation (PanelExpanderButtons):
http://gojs.net/latest/intro/buttons.html
and it never mentioned that I should name a graphObject “COLLAPSIBLE”.
Here is what is said : “The second argument to GraphObject.make should be a string that names the element in the node whose GraphObject.visible property you want the button to toggle”.

Following your advice, I understand that I can have only one PanelExpanderButtons per node, because if I want to make multiple button how are they suppose to know wich panel to collapse/expand ?

Here is the modified part of ccode following your advice:

        new go.Binding("itemArray", "tubes"),{
            itemTemplate:
                GOJS(go.Panel, "Table",{ column: 0 },
                    GOJS(go.TextBlock, new go.Binding("text", "tube"),{column: 0,margin: 4}),
                    GOJS("PanelExpanderButton", "COLLAPSIBLE",{column: 1}),
                    GOJS(go.Panel, "Vertical",{
                        name : "COLLAPSIBLE",
                        padding: 2,
                        itemTemplate: fieldTemplate,
                        row : 1,
                        column: 0,
                        columnSpan: 2
                    },
                    new go.Binding("itemArray", "fibers"))
                )
            }

Here is the rendering:

I have no error anymore, but the expander button is now working.

Actually, you can have multiple "PanelExpanderButton"s in a Part – in fact that GoJS Buttons -- Northwoods Software page demonstrates that.

However, the current definition of “PanelExpanderButton”, given in extensions/Buttons.js, does not support nesting of those buttons in itemTemplates. Here is the new definition of “PanelExpanderButton” that will be in version 1.7. Until you upgrade to 1.7, you can use this:

go.GraphObject.defineBuilder("PanelExpanderButton", function(args) {
  var eltname = /** @type {string} */ (go.GraphObject.takeBuilderArgument(args, "COLLAPSIBLE"));

  var button = /** @type {Panel} */ (
    go.GraphObject.make("Button",
      { // set these values for the visible binding conversion
        "_buttonExpandedFigure": "TriangleUp",
        "_buttonCollapsedFigure": "TriangleDown"
      },
      go.GraphObject.make(go.Shape, "TriangleUp",
                          { name: "ButtonIcon", desiredSize: new go.Size(6, 4) },
                          new go.Binding("figure", "visible",
                                         function(vis) { return vis ? button["_buttonExpandedFigure"] : button["_buttonCollapsedFigure"]; })
                              .ofObject(eltname)))
  );

  var border = button.findObject("ButtonBorder");
  if (border instanceof go.Shape) {
    border.stroke = null;
    border.fill = "transparent";
  }

  button.click = function(e, button) {
    var diagram = button.diagram;
    if (diagram === null) return;
    if (diagram.isReadOnly) return;
    var elt = button.findTemplateBinder();
    if (elt === null) elt = button.part;
    if (elt !== null) {
      var pan = elt.findObject(eltname);
      if (pan !== null) {
        diagram.startTransaction('Collapse/Expand Panel');
        pan.visible = !pan.visible;
        diagram.commitTransaction('Collapse/Expand Panel');
      }
    }
  }

  return button;
});

With this definition, you can use them inside itemTemplates for expanding or collapsing elements within the item. Here is an example:

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        $(go.Shape, { fill: "white" }),
        $(go.Panel, "Table",
          { margin: 0.5 },
          $(go.RowColumnDefinition, { row: 0, background: "lightgray" }),
          $(go.TextBlock, { column: 0, margin: new go.Margin(2, 2, 0, 2) },
            new go.Binding("text", "key")),
          $("PanelExpanderButton", { column: 1, background: "lightgray", alignment: go.Spot.Right }),
          $(go.Panel, "Table",
            { name: "COLLAPSIBLE", row: 1, columnSpan: 2 },
            new go.Binding("itemArray", "items"),
            {
              itemTemplate:
                $(go.Panel, "TableColumn",
                  $(go.Panel, "Table", { row: 0, stretch: go.GraphObject.Fill },
                    $(go.TextBlock, { column: 0 },
                      new go.Binding("text", "name")),
                    $("PanelExpanderButton", { column: 1 })
                  ),
                  $(go.Panel, "Table", { name: "COLLAPSIBLE", row: 1, alignment: go.Spot.Top },
                    new go.Binding("itemArray", "details"),
                    {
                      itemTemplate:
                        $(go.Panel, "TableRow",
                          $(go.TextBlock, new go.Binding("text", ""))
                        )
                    }
                  )
                )
            }
          )
        )
      );

    myDiagram.model = new go.GraphLinksModel([
      {
        key: "Alpha",
        items: [
          {
            name: "A",
            details: [
              "alpha",
              "apple",
              "active"
            ]
          },
          {
            name: "B",
            details: [
              "beta",
              "boat"
            ]
          },
          {
            name: "C",
            details: [
              "gamma",
              "cat",
              "car",
              "computer"
            ]
          }
        ]
      },
      {
        key: "Beta",
      }
    ],[
      { from: "Alpha", to: "Beta" }
    ]);
  }

This appears as:

After collapsing “C”:

I just paste your code changing:

go.GraphObject.make(Shape, “TriangleUp”,

in

go.GraphObject.make(“Shape”, “TriangleUp”,

And it is working !
I will ask one more thing, is it possible to have a default colapsed or expanded depending on my data ?

Thank you.

Thanks for the typo fix.

Sure, just do a new go.Binding("visible", ... on the “COLLAPSIBLE” element.

If you want it to be collapsed by default, just set { visible: false } on that “COLLAPSIBLE” element.

Great, thank you.
Problem solved !