Interacting with the tree may have many faces. You e.g. might need to:
- react to clicking on tree nodes,
- traversing the tree by expanding nodes,
- selecting / multiselecting tree nodes.
Also you might need to change the tree state by invoking external actions, e.g. clicking the external button to:
- expand relevant tree path,
- change tree's selection.
Let's think of following application (run example). I provide functionality of traversing the tree with two external buttons (it's a wizard like navigation - Next - Previous - relation). I also provide expansion of tree node by clicking a button (I've hard-coded 'Web containers' node to be expanded).
How does it work
How does it work
To implement the tree I used Java Server Faces 2.1 web MVC with RichFaces 4.5.4 <rich:tree> component. On the xhtml side I configured it in the following way:
<rich:tree id="tree" selectionType="ajax" value="#{webTechnologiesTreeBean.rootNode}" var="node" selection="#{webTechnologiesTreeBean.selection}" selectionChangeListener="#{webTechnologiesTreeBean.processTreeSelectionChange}"> <rich:treeNode expanded="#{node.expanded}" iconLeaf="images/mobilne.jpg"> <h:outputText value="#{node.data.name}"/> </rich:treeNode> </rich:tree>
On the managed bean side i've bound component properties in the following way (selection to WebTechnologiesTreeBean) :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| @ManagedBean @SessionScoped public class WebTechnologiesTreeBean implements Serializable, ITree { private Collection<Object> selection = new ArrayList<Object>() @Override public Collection<Object> getSelection() { return selection; } public void setSelection(Collection<Object> selection) { this.selection = selection; } (..) } |
... and expansion to WebTechnologiesTreeNode class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public class WebTechnologiesTreeNode extends TreeNodeImpl implements Serializable{ private boolean expanded = false; public boolean isExpanded() { return expanded; } public void setExpanded(boolean expanded) { this.expanded = expanded; } (..) } |
The whole tree model has been built using Builder design pattern implemented inside WebTechnologiesTreeNode. This building process includes passing data to nodes and node keys which are node's indentifiers within a tree. Leaf node's keys are auto-numerated with "1", "2" etc.. Using this String typed keys i am able to retrieve relevant node later on.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| private WebTechnologiesTreeNode createRootNode() {
WebTechnologiesTreeNode result = new WebTechnologiesTreeNode.NodeBuilder().build();
WebTechnologiesTreeNode frameworkNode = new WebTechnologiesTreeNode.NodeBuilder()
.withData(new SimpleNodeData("Web frameworks"))
.withChildLeaf(new WebLinkNodeData("Java server faces", "https://javaserverfaces.java.net/"))
.withChildLeaf(new WebLinkNodeData("Vaadin", "https://vaadin.com/home"))
.withChildLeaf(new WebLinkNodeData("Spring MVC", "http://projects.spring.io/spring-framework/"))
.withChildLeaf(new WebLinkNodeData("Play", "https://www.playframework.com/"))
.withChildLeaf(new WebLinkNodeData("Struts", "https://struts.apache.org/"))
.build();
WebTechnologiesTreeNode containerNode = new WebTechnologiesTreeNode.NodeBuilder()
.withData(new SimpleNodeData("Web containers"))
.withChildLeaf(new WebLinkNodeData("Tomcat", "http://tomcat.apache.org/"))
.withChildLeaf(new WebLinkNodeData("Glassfish", "https://glassfish.java.net/"))
.withChildLeaf(new WebLinkNodeData("JBoss", "http://www.jboss.org/"))
.build();
result.addChild("frameworks", frameworkNode);
result.addChild("containers", containerNode);
return result;
}
|
Handling expansion programatically (server-side)
Now, when I've got data model, property bindings I can collapse / expand my hard-coded node with key 'containers' (display name 'Web containers').
1
2
3
4
5
| public void switchContainersExpansion() { WebTechnologiesTreeNode node = (WebTechnologiesTreeNode) rootNode.getChild("containers"); node.setExpanded(!node.isExpanded()); } |
Handling selection on server side
In RichFaces 4.5.X selection is kept with List<SequenceRowKey> each SequenceRowKey instance has a path consisted of tree node string keys. For example, in my demo app, path to 'Java Server Faces' tree node would be SequenceRowKey["frameworks", "0"], path to 'JBoss' node would be SequenceRowKey["containers", "2"].
To programatically set single selection on <rich:tree> I have to set one element list in bound selection property. Let's say I want to set 'JBoss' selected:
1
2
3
| Collection<Object> mySelection = new ArrayList(); mySelection.add(new SequenceRowKey("containers", "2")); treeBean.setSelection(mySelection); |
Please feel free to review source code of my example application and see GitHub repository.
1 comment:
Very useful!
Post a comment