Search code examples
gwtuibinder

Using a TreeItem with a Widget as content in a single GWT UiBinder template


I am attempting to initialise a TreeItem with a Widget defined within a UI Binder template as the TreeItem's content. Initially I started with a template like this:

<g:Tree>
    <g:TreeItem>
        <g:HTMLPanel>
            <p>This is the root item's content.</p>
        </g:HTMLPanel>
        <g:TreeItem>
            <g:HTMLPanel>
                <p>This is the child's content.</p>
            </g:HTMLPanel>
        </g:TreeItem>
    </g:TreeItem>
</g:Tree>

Expecting to end up with a tree structure something like this:

+ This is the root item's content.

Expanding to:

- This is the root item's content.
 \ This is the child's content.

But this doesn't work. The HTMLPanel widgets are created as children of the TreeItems, rather than being the items' widgets, so I end up with a structure like this:

- (root item has no content)
 \ This is the root item's content.
  - (first child has no content)
   \ This is the child's content.

So I tried extending the TreeItem class like so:

public class WidgetTreeItem extends TreeItem {

    @UiChild(tagname="widget", limit=1)
    public void setWidget(IsWidget isWidget) {
        super.setWidget(isWidget.asWidget());
    }

}

And then, importing the package containing WidgetTreeItem into the c namespace, I have a template like this:

<g:Tree>
    <c:WidgetTreeItem>
        <c:widget>
            <g:HTMLPanel>
                <p>This is the root item's content.</p>
            </g:HTMLPanel>
        </c:widget>
        <!-- Should create a child TreeItem with the HTMLPanel as its Widget. -->
        <g:HTMLPanel>
            <p>This is the child's content.</p>
        </g:HTMLPanel>
    </c:WidgetTreeItem>
</g:Tree>

But this doesn't work, either. It fails with the following exception:

Only TreeItem or Widget subclasses are valid children: <c:WidgetTreeItem>.

Can anyone see how to achieve what I am attempting?


Solution

  • Given a little inspiration from this answer, I have found my solution. Given my original example, the XML now looks like this:

    <g:Tree>
        <g:HTMLPanel ui:field="rootContent">
            <p>This is the root item's content.</p>
        </g:HTMLPanel>
        <g:HTMLPanel ui:field="childContent">
            <p>This is the child's content.</p>
        </g:HTMLPanel>
        <g:TreeItem widget="{rootContent}">
            <g:TreeItem widget="{childContent}">
            </g:TreeItem>
        </g:TreeItem>
    </g:Tree>
    

    Some playing around was required here. Most notably, this only works provided that the content panels are contained within a widget implementing the HasWidgets interface. The Tree class satisfies this requirement. It is also worth noting that the content fields must be defined before they are used.