• cdi
  • components
  • contexts
  • converters
  • eventlisteners
  • exceptionhandlers
  • facesviews
  • filters
  • functions
  • managedbeans
  • renderkits
  • resourcehandlers
  • scripts
  • taghandlers
  • utils
  • validators
-
  • cache
  • commandScript
  • componentIdParam
  • conditionalComment
  • form
  • highlight
  • messages
  • onloadScript
  • outputFormat
  • outputLabel
  • param
  • resourceInclude
  • tree
  • viewParam

Description

The <o:tree> allows the developers to have full control over the markup of a tree hierarchy by declaring the appropriate JSF components or HTML elements in the markup. The <o:tree> does namely not render any HTML by itself.

Note that the left menu of this showcase application is also using an <o:tree> which is dynamically populated in an application scoped bean based on the structure of the webapp's /showcase folder. See also App source code, Page source code and layout.xhtml source code. Also note that Page extends ListTreeModel, this is not necessary per se, but it eases accessing the parent and sister pages in EL as is done in the navigation menu here above, and the siblings as is done in the quick navigation buttons right above. See also showcase.xhtml source code.

If you need a tree whereby the children are sorted based on their Comparable implementation, then use SortedTreeModel instead of ListTreeModel.

In the below editable tree example, all input values are required. Clear some of them and then submit to see proper validation message handling. If all values are valid, then the static tree will also be updated with submitted values. You can also dynamically add/remove nodes.

Demo

Static tree

0 One

  • 0_0 Two
  • 0_1 Three

1 Four

  • 1_0 Five

Editable tree

(only for this view scope ;) )
Source code
<h3>Static tree</h3>
<h:panelGroup id="staticTree">
    <o:tree value="#{treeBean.tree}" var="exampleEntity" varNode="node">
        <o:treeNode level="0">
            <o:treeNodeItem>
                <h4>#{node.index} #{exampleEntity.value}</h4>
                <o:treeInsertChildren />
            </o:treeNodeItem>
        </o:treeNode>
        <o:treeNode>
            <ul>
                <o:treeNodeItem>
                    <li>
                        #{node.index} #{exampleEntity.value}
                        <o:treeInsertChildren />
                    </li>
                </o:treeNodeItem>
            </ul>
        </o:treeNode>
    </o:tree>
</h:panelGroup>

<hr/>

<h3>Editable tree</h3>
<h:form id="form">
    <c:set var="saveButtonPressed" value="#{param['javax.faces.source'] == 'form:save'}" />
    <h:commandButton id="addNode" value="Add new node" action="#{treeBean.addChild(treeBean.tree)}">
        <f:ajax execute="@form" render="@form" />
    </h:commandButton>
    <o:tree id="tree" value="#{treeBean.tree}" var="exampleEntity" varNode="node">
        <o:treeNode>
            <ul>
                <o:treeNodeItem>
                    <li>
                        <h:inputText id="value" value="#{exampleEntity.value}" styleClass="treeinput"
                            required="#{saveButtonPressed}" requiredMessage="Please enter value" />
                        <h:commandButton id="addChild" value="Add new child" action="#{treeBean.addChild(node)}"
                            rendered="#{node.level lt 10}">
                            <f:ajax execute="@form" render="@form" />
                        </h:commandButton>
                        <h:commandButton id="remove" value="Remove node" action="#{treeBean.remove(node)}">
                            <f:ajax execute="@form" render="@form" />
                        </h:commandButton>
                        <h:message for="value" />
                        <o:treeInsertChildren />
                    </li>
                </o:treeNodeItem>
            </ul>
        </o:treeNode>
    </o:tree>
    <h:commandButton id="save" value="Save" action="#{treeBean.save}">
        <f:ajax execute="@form" render="@form" />
    </h:commandButton> (only for this view scope ;) )
    <h:outputText value="OK!" rendered="#{facesContext.postback and not facesContext.validationFailed}" />
</h:form>

<h:outputScript>
    /**
     * Force input elements to invoke "Save" button on enter key instead of one of those "add"/"remove" buttons.
     */
    $(document).on("keypress", ".treeinput", function(event) {
        if (event.keyCode == 13) {
            $(this).closest("form").find("[id$=save]").click();
            return false;
        }
    });
</h:outputScript>
<o:onloadScript>
    /**
     * Focus the first empty input element on every ajax response.
     */
    $(".treeinput:not([value]):first").focus();
</o:onloadScript>