JBoss.orgCommunity Documentation
Read this chapter for details on components that use tree structures.
The <rich:tree>
component provides a hierarchical tree control. Each <rich:tree>
component typically consists of <rich:treeNode>
child components. The appearance and behavior of the tree and its nodes can be fully customized.
The <rich:tree>
component requires the value
attribute to point to the data model for populating the tree. The data model must be either an org.richfaces.model.TreeNode
interface, an org.richfaces.model.TreeDataModel
interface, or a javax.swing.tree.TreeNode
interface. The var
attribute declares the variable used for iterating through the data model, so that child <rich:treeNode>
components can reference each iteration.
Ideally, the <rich:tree>
component needs one or more <rich:treeNode>
components to work with the data model. However if no <rich:treeNode>
components are provided the tree creates default nodes instead.
Example 12.1. Basic usage
This example demonstrates basic usage of the <rich:tree>
component using an org.richfaces.model.TreeNode
data model.
The data model is constructed as follows:
private TreeNodeImpl<String> stationRoot = new TreeNodeImpl<String>();
private TreeNodeImpl<String> stationNodes = new TreeNodeImpl<String>();
private String[] kickRadioFeed = { "Hall & Oates - Kiss On My List",
"David Bowie - Let's Dance",
"Lyn Collins - Think (About It)",
"Kim Carnes - Bette Davis Eyes",
"KC & the Sunshine Band - Give It Up" };
stationRoot.setData("KickRadio");
stationNodes.addChild(0, stationRoot);
for (int i = 0; i < kickRadioFeed.length; i++){
TreeNodeImpl<String> child = new TreeNodeImpl<String>();
child.setData(kickRadioFeed[i]);
stationRoot.addChild(i, child);
}
The tree then accesses the nodes of the model using the station
variable:
<rich:tree value="#{stations.stationNodes}" var="station">
<rich:treeNode>
<h:outputText value="#{station}" />
</rich:treeNode>
</rich:tree>
Different nodes in the tree can have different appearances, such as node icons, depending on the type of data the node contains. Use the nodeType
attribute to differentiate the types of nodes; the node is then rendered according to the <rich:treeNode>
component with the corresponding type
attribute. Example 12.2, “nodeType attribute” shows a <rich:tree>
component with three different child <rich:treeNode>
components defined to represent three different node appearances. Refer to Section 12.1.8.2, “Appearance” for details on customizing the appearance of <rich:treeNode>
components.
Example 12.2. nodeType
attribute
<rich:tree style="width:300px" value="#{library.data}" var="item" nodeType="#{item.type}">
<rich:treeNode type="artist" iconExpanded="/images/tree/singer.png" iconCollapsed="/images/tree/singer.png">
<h:outputText value="#{item.name}" />
</rich:treeNode>
<rich:treeNode type="album" iconExpanded="/images/tree/disc.png" iconCollapsed="/images/tree/disc.png">
<h:outputText value="#{item.album}" />
</rich:treeNode>
<rich:treeNode type="song" iconLeaf="/images/tree/song.png">
<h:outputText value="#{item.title}" />
</rich:treeNode>
</rich:tree>
If the nodeType
attribute returns null, the node is rendered as a "typeless" (or default) node. The typeless node is the first child <rich:treeNode>
component with a valid rendered
attribute, but without a defined type
attribute.
If the nodeType
attribute is not included and there are no child <rich:treeNode>
components, the tree constructs a default node itself.
Icons for different nodes and node states can be defined for the whole tree using the following attributes:
iconLeaf
The iconLeaf
attribute points to the icon to use for any node that does not contain any child nodes.
iconExpanded
and iconCollapsed
The iconExpanded
and iconCollapsed
attributes point to the icons to use for expanded and collapsed nodes respectively. If these attributes are defined, the icon
attribute is not used.
The mode for performing submissions when nodes are expanded or collapsed is determined by the toggleType
attribute, which can have one of the following three values:
ajax
This is the default setting. The <rich:tree>
component performs an Ajax form submission, and only the content of the tree is rendered.
server
The <rich:tree>
component performs a common submission, completely re-rendering the page.
client
The <rich:tree>
component updates on the client side, re-rendering itself and any additional components listed with the render
attribute.
By default, the event to expand or collapse a tree node is a mouse click. To specify a different event, use the toggleNodeEvent
attribute.
The mode for performing submissions when nodes are selected is determined by the selectionType
attribute, which can have one of the following three values:
ajax
This is the default setting. The <rich:tree>
component performs an Ajax form submission, and only the content of the tree is rendered.
server
The <rich:tree>
component performs a common submission, completely re-rendering the page.
client
The <rich:tree>
component updates on the client side, re-rendering itself and any additional components listed with the render
attribute.
If the <rich:tree>
component uses a custom data model, the data model provides unique keys for tree nodes so they can be identified during a client request. The <rich:tree>
component can use strings as key values. These strings may contain special characters that are not allowed by browsers, such as the left angle bracket (<) and ampersand (&). To allow these characters in the keys, a row key converter must be provided.
To apply a converter to the <rich:tree>
component, define it with the rowKeyConverter
attribute.
In addition to the standard Ajax events and HMTL events, the <rich:tree>
component uses the following client-side events:
The nodetoggle
event is triggered when a node is expanded or collapsed.
The beforenodetoggle
event is triggered before a node is expanded or collapsed.
The selectionchange
event is triggered when a node is selected.
The beforeselectionchange
event is triggered before a node is selected.
The <rich:tree>
component uses the following server-side listeners:
The toggleListener
listener processes expand and collapse events.
The selectionChangeListener
listener processes the request when a node is selected.
component-type
: org.richfaces.tree
component-class
: org.richfaces.component.html.Htmltree
component-family
: org.richfaces.tree
renderer-type
: org.richfaces.treeRenderer
tag-class
: org.richfaces.taglib.treeTag
The <rich:treeNode>
component is a child component of the <rich:tree>
component. It represents nodes in the parent tree. The appearance and functionality of each tree node can be customized.
The <rich:treeNode>
component must be a child of a <rich:tree>
component. It does not need any attributes declared for basic usage, but can provide markup templates for tree nodes of particular types. Refer to Example 12.1, “Basic usage” for an example of basic <rich:treeNode>
component usage.
Refer to Section 12.1.2, “Appearance” for the <rich:tree>
component for details and examples on styling nodes and icons. Icon styling for individual <rich:treeNode>
components uses the same attributes as the parent <rich:tree>
component: iconLeaf
, iconExpanded
, and iconCollapsed
. Icon-related attributes specified for child <rich:treeNode>
components overwrite any global icon attributes of the parent <rich:tree>
component.
Use the rendered
attribute to determine whether the node should actually be rendered in the tree or not. Using the rendered
attribute in combination with the <rich:treeNode>
type
attribute can allow further style differentiation between node content, as shown in Example 12.3, “rendered attribute”.
Example 12.3. rendered
attribute
The rendered
attribute is used to differentiate between music albums that are in stock and those that are not. The item type
attributes return values that are otherwise identical; only the item.exist property differs, so it is used for the rendered
attribute.
<rich:tree style="width:300px" value="#{library.data}"
var="item" nodeFace="#{item.type}">
...
<rich:treeNode type="album" iconLeaf="/images/tree/album.gif"
rendered="#{item.exist}">
<h:outputText value="#{item.name}" />
</rich:treeNode>
<rich:treeNode type="album" iconLeaf="/images/tree/album_absent.gif"
rendered="#{not item.exist}">
<h:outputText value="#{item.name}" />
</rich:treeNode>
...
</rich:tree>
Interactivity with individual nodes, such as expanding, collapsing, and other event handling, can be managed by the parent <rich:tree>
component. Refer to Section 12.1.3, “Expanding and collapsing tree nodes” and Section 12.1.6, “Event handling” for further details.
Use the expanded
attribute to determine whether the node is expanded or collapsed.
Use a tree adaptor to populate a tree model declaratively from a non-hierarchical model, such as a list or a map.
The <rich:treeModelAdaptor>
component takes an object which implements the Map
or Iterable
interfaces. It adds all the object entries to the parent node as child nodes.
The <rich:treeModelAdaptor>
component is added as a nested child component to a <rich:tree>
component, or to another tree adaptor component.
The <rich:treeModelAdaptor>
component requires the nodes
attribute for basic usage. The nodes
attribute defines a collection of elements to iterate through for populating the nodes.
Define the appearance of each node added by the adaptor with a child <rich:treeNode>
component. Refer to Section 12.1.8, “<rich:treeNode>” for details on the <rich:treeNode>
component.
<rich:treeModelAdaptor>
components can further be nested in other <rich:treeModelAdaptor>
components to subsequently populate lower levels of the tree.
To access the current element at each iteration, use the var
attribute of either the parent <rich:tree>
component or the <rich:treeModelAdaptor>
component itself. Example 12.4, “Nested <rich:treeModelAdaptor> components” demonstrates a series of nested <rich:treeModelAdaptor>
components, each using the parent's var
attribute to reference the current element.
Example 12.4. Nested <rich:treeModelAdaptor> components
<rich:tree>
<rich:treeNodesAdaptor id="project" nodes="#{loaderBean.projects}" var="project">
<rich:treeNode>
<h:commandLink action="#{project.click}" value="Project: #{project.name}" />
</rich:treeNode>
<rich:treeNodesAdaptor id="srcDir" var="srcDir" nodes="#{project.srcDirs}">
<rich:treeNode>
<h:commandLink action="#{srcDir.click}" value="Source directory: #{srcDir.name}" />
</rich:treeNode>
<rich:treeNodesAdaptor id="pkg" var="pkg" nodes="#{srcDir.packages}">
<rich:treeNode>
<h:commandLink action="#{pkg.click}" value="Package: #{pkg.name}" />
</rich:treeNode>
<rich:treeNodesAdaptor id="class" var="class" nodes="#{pkg.classes}">
<rich:treeNode>
<h:commandLink action="#{class.click}" value="Class: #{class.name}" />
</rich:treeNode>
</rich:treeNodesAdaptor>
</rich:treeNodesAdaptor>
</rich:treeNodesAdaptor>
</rich:treeNodesAdaptor>
</rich:tree>
Each <rich:treeModelAdaptor>
component is mapped to a list of objects. During the iteration, the corresponding object properties are used to define the node labels and actions, and are in turn used for iterating through nested lists.
Adaptors that use Map
interfaces or models with non-string keys require a row key converter in order to correctly identify nodes. Refer to Section 12.1.5, “Identifying nodes with the rowKeyConverter attribute” for details on the use of the rowKeyConverter
attribute.
Adaptors that use Iterable
interfaces have simple integer row keys. A default converter is provided and does not need to be referenced explicitly.
The <rich:treeModelRecursiveAdaptor>
component iterates through recursive collections in order to populate a tree with hierarchical nodes, such as for a file system with multiple levels of directories and files.
The <rich:treeModelRecursiveAdaptor>
component is an extension of the <rich:treeModelAdaptor>
component. As such, the <rich:treeModelRecursiveAdaptor>
component uses all of the same attributes. Refer to Section 12.2.1, “<rich:treeModelAdaptor>” for details on the <rich:treeModelAdaptor>
component.
In addition, the <rich:treeModelRecursiveAdaptor>
component requires the root
attribute. The root
attribute defines the collection to use at the top of the recursion. For subsequent levels, the node
attribute is used for the collection.
Example 12.5, “Basic usage” demonstrates how the <rich:treeModelRecursiveAdaptor>
component can be used in conjunction with the <rich:treeModelAdaptor>
component to recursively iterate through a file system and create a tree of directories and files.
Example 12.5. Basic usage
<rich:tree var="item">
<rich:treeModelRecursiveAdaptor roots="#{fileSystemBean.sourceRoots}" nodes="#{item.directories}" >
<rich:treeNode>
#{item.shortPath}
</rich:treeNode>
<rich:treeModelAdaptor nodes="#{item.files}">
<rich:treeNode>#{item}</rich:treeNode>
</rich:treeModelAdaptor>
</rich:treeModelRecursiveAdaptor>
</rich:tree>
The <rich:treeModelRecursiveAdaptor>
component references the FileSystemBean
class as the source for the data.
@ManagedBean
@RequestScoped
public class FileSystemBean {
private static final String SRC_PATH = "/WEB-INF";
private List<FileSystemNode> srcRoots;
public synchronized List<FileSystemNode> getSourceRoots() {
if (srcRoots == null) {
srcRoots = new FileSystemNode(SRC_PATH).getDirectories();
}
return srcRoots;
}
}
The FileSystemBean
class in turn uses the FileSystemNode
class to recursively iterate through the collection.
public class FileSystemNode {
...
public synchronized List<FileSystemNode> getDirectories() {
if (directories == null) {
directories = Lists.newArrayList();
Iterables.addAll(directories, transform(filter(getResourcePaths(), containsPattern("/$")), FACTORY));
}
return directories;
}
public synchronized List<String> getFiles() {
if (files == null) {
files = new ArrayList<String>();
Iterables.addAll(files, transform(filter(getResourcePaths(), not(containsPattern("/$"))), TO_SHORT_PATH));
}
return files;
}
private Iterable<String> getResourcePaths() {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
Set<String> resourcePaths = externalContext.getResourcePaths(this.path);
if (resourcePaths == null) {
resourcePaths = Collections.emptySet();
}
return resourcePaths;
}
...
}
The getDirectories()
function is used recursively until the object has the collection of children. The model adaptor calls the getFiles()
function at each level in order to add the file nodes.
The resulting tree hierarchically lists the directories and files in the collection.
Adaptors that use Map
interfaces or models with non-string keys require a row key converter in order to correctly identify nodes. Refer to Section 12.1.5, “Identifying nodes with the rowKeyConverter attribute” for details on the use of the rowKeyConverter
attribute.
Adaptors that use Iterable
interfaces have simple integer row keys. A default converter is provided and does not need to be referenced explicitly.