Saturday, 18 April 2015

Interactions with RichTree

Possible cases

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.


Working example ilustrating the use case

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

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.

2 comments:

Unknown said...

Very useful!

magdalinavalbuena said...

Casinos in Maryland - JTM Hub
Looking for casinos to enjoy live table games? Our recommended casinos in Maryland. See the best 파주 출장안마 slots, video poker and live 부천 출장마사지 casino in What are the top-rated casinos in 순천 출장마사지 Maryland?How much 인천광역 출장샵 does it 포천 출장안마 cost to play at a casino in Maryland?