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

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 markup by itself.

The component value must point to a tree of data objects represented by a TreeModel instance, typically established via a ValueExpression. During iterative processing over the nodes of tree in the tree model, the object for the current node is exposed as a request attribute under the key specified by the var attribute. The node itself is exposed as a request attribute under the key specified by the varNode attribute.

Only children of type TreeNode are allowed and processed by this component.

Here is a basic usage example:

 <o:tree value="#{bean.treeModel}" var="item" varNode="node">
     <o:treeNode>
         <ul>
             <o:treeNodeItem>
                 <li>
                     #{node.index} #{item.someProperty}
                     <o:treeInsertChildren />
                 </li>
             </o:treeNodeItem>
         </ul>
     </o:treeNode>
 </o:tree>

treeNode

The <o:treeNode> is an UIComponent that represents a single tree node within a parent Tree component. Within this component, the var attribute of the parent Tree component will expose the tree node. Each of its children is processed by TreeNodeItem.

The level attribute can be used to specify for which tree node level as obtained by TreeModel.getLevel() this component should render the children by TreeNodeItem. The root tree node has level 0.

treeNodeItem

The <o:treeNodeItem> is an UIComponent that represents a single child tree node within a parent TreeNode component. Within this component, the var attribute of the parent Tree component will expose the child tree node.

This component allows a child component of type TreeInsertChildren which indicates the place to insert the children of the current child tree node recursively by a TreeNode component associated with the children's level in the same parent Tree component.

treeInsertChildren

The <o:treeInsertChildren> is an UIComponent that represents the insertion point for the children of a parent tree node which is represented by TreeNodeItem.

This component does not allow any children.

Showcase

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.

Demo

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.

Static tree

0 One

  • 0_0 Two
  • 0_1 Three

1 Four

  • 1_0 Five

Editable tree

(only for this view scope ;) )
Source code
<p>
    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.
</p>

<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>