Customized Richfaces Tree
Yesterday I had to customize the Richfaces tree component, because my client wants a special layout. My solution is a little bit strange. I share it here for someone which is in the same situation
Here is the story …
Per default the rich:tree looks like a standard tree browser (i.e. explorer, eclipse, whatever):

But I want this look:

You see that the expand/collapse icon (
) is on the same level with the node-icon (
). That’s very hard to fix this with CSS (it’s possible but i prefer my strange solution
). The Richfaces documentation describes which parts of a tree could be customize.

We have:
- rich-tree-node-handle and rich-tree-node-handleicon – a td which contains a link and a image to expand/collapse the node (only possible for a node not a leaf)
- rich-tree-node-icon – is a td which contains the image for a node (a node with children)
- rich-tree-node-icon-leaf – is a td which contains the image for a leaf (a node without children)
I decide to move the expand/collapse icon from the handle-td to the icon-td and “simulate” the user-click with Javascript:

Listing 1 tree.xhtml:
<rich:tree id="tree"
binding="#{treeBean.tree}"
var="item"
switchType="ajax"
ajaxSubmitSelection="true"
toggleOnClick="false"
showConnectingLines="false"
disableKeyboardNavigation="true">
<f:facet name="iconCollapsed">
<!-- no image for collapsed -->
<rich:spacer width="0" height="0" style="border: none;"/>
</f:facet>
<f:facet name="iconExpanded">
<!-- no image for expanded -->
<rich:spacer width="0" height="0" style="border: none;"/>
</f:facet>
<f:facet name="icon">
<!-- use normal node icon to toggle expand/collapse -->
<h:panelGroup>
<h:graphicImage value="#{item.isLeaf ? '/images/leaf.gif' : '/images/collapsed.gif'}"
onclick="myToggleTreeNode(this);"
rendered="#{!treeBean.isExpanded}"/>
<h:graphicImage value="#{item.isLeaf ? '/images/leaf.gif' : '/images/expanded.gif'}"
onclick="myToggleTreeNode(this);"
rendered="#{treeBean.isExpanded}"/>
</h:panelGroup>
</f:facet>
<f:facet name="iconLeaf">
<h:graphicImage value="/images/leaf.gif"/>
</f:facet>
<rich:recursiveTreeNodesAdaptor roots="#{treeBean.roots}" var="item" nodes="#{item.children}">
<rich:treeNode>
<h:outputText value="#{item.name}"/>
</rich:treeNode>
</rich:recursiveTreeNodesAdaptor>
</rich:tree>
Listing 2 tree.js:
function myToggleTreeNode(element) {
var elem = jQuery(element);
// img -> span -> td
var parent = elem.parent().parent();
var elementId = parent.attr("id");
// i.e. j_id31:tree:j__id39:18::j_id40:icon -> the td arround the icon-image
var index = elementId.lastIndexOf(":icon");
var treeNodeId = elementId.substring(0, index);
// i.e. j_id31:tree:j__id39:18::j_id40:handle -> the td arround the original expand/collapse-image
var handleId = treeNodeId+':handle';
// pure jQuery not working here
var expandElement = jQuery($(handleId));
expandElement.trigger("click");
}
Listing 3 tree.css:
.rich-tree-node-handleicon {
display: none;
}