1 2 Previous Next 15 Replies Latest reply on Nov 14, 2012 1:49 PM by volothamp

    rich:tree - programatically set the selected node and expand

    kingcu

      In my use case, I have a business tree (a parent business could have any number of child businesses) and a page for searching businesses by name. Assume the following tree:

      A
      --A1
      ----AA1
      --A2

      where A has two children A1 and A2, A1 has one child AA1.

      If use selects AA1 from the search results, I need the tree being displayed in such a way that the tree is expanded with AA1 selected. I can't seem to find any API that allows me to either expand the tree or set the selection. Any hint on this? Thanks in advance.

        • 1. Re: rich:tree - programatically set the selected node and ex
          kingcu

          Can someone please let me know if this is possible? Thanks.

          • 2. Re: rich:tree - programatically set the selected node and ex
            max76

            Hi,

            just have a look at the HtmlTree (and also the UITree) API. There are methods for controlling the expansion state of the tree: look at queueXXX() methods.

            i successfully testet collapseAll and expandAll. collapsing and expansion if single nodes should also work somehow.

            hope that helps...

            ---
            max

            • 3. Re: rich:tree - programatically set the selected node and ex
              kingcu

              Thanks Max for your reply.

              The question I have now is that how I can get to UITree: I know that if I attach an event listener to the tree, I can get to UITree through the event source; but, in my case, I need to set the expansion point when I build the tree data model and before the tree starts to render. In other words, I want the tree to be displayed with the specific node expanded at the very beginning instead of later when some user action triggers.

              • 4. Re: rich:tree - programatically set the selected node and ex
                max76

                Hello,

                hmmm, good question, i dont know how that is possible (if it is possible), but i think there may be something like interceptors that may be called before a page is rendered...

                One possible solution that should work would be an UIComponent property in your bean that is bound to the tree (so you have an instance to the HtmlTree when a plain action is called) and some client script that calls an action of your bean when the view is loaded; this action expands the nodes and then the tree is reloaded...

                i think on registering java-script code at body.onload, call an action with a4j:jsfunction (ajax4jsf) and rerender just your tree (ajaxstyle)...

                sure, thats a workaround, no solution to your problem.

                --
                max

                • 5. Re: rich:tree - programatically set the selected node and ex
                  kingcu

                  Thanks. Sounds like a plan. One more question: in the onload actionListener, I can get the UIComponent and then cast it to a HtmlTree, but is there any API that allows me to traverse it? Because I need to compare each tree node with the previously selected business id to determine if this is the node to expand to.

                  • 6. Re: rich:tree - programatically set the selected node and ex
                    max76

                    i dont think there is an easy and intuitive way to do so...

                    you can try to struggle with getTreeNode() and getTreeNode(java.lang.Object rowKey) methods.

                    For me i am still unable to expand a given node, i dont know by now how exactly node expansion works... it looks like you must provide some sort of path (with node ids) to the node you wish to expand... but for now i can only exand one level after another :-(

                    maybe a short hint from someone would help!

                    thanks,
                    max

                    • 7. Re: rich:tree - programatically set the selected node and ex
                      max76

                      just solved node-expansion to a given node...

                      i had to expand all container_nodes on the way to a given node manually, that means you must queue a nodeExpansion for every parentnode.

                      hope that helps...

                      • 8. Re: rich:tree - programatically set the selected node and ex
                        mugwump

                        Hi max,

                        I got the same problem and try to make sense of your last post: The API-Documentation for the tree is awful, so could you please elaborate a little more on your solution?!

                        "queue a nodeExpansion": Meaning exactly what?! In javascript in the client? On the server on the UITree before the page gets rendered (still trying to figure out how to do this: Maybe build the UITree and then bind it?!)
                        thx for any help!
                        stf

                        • 9. Re: rich:tree - programatically set the selected node and ex
                          kingcu

                          I got my tree working to a point where I could programmatically do a expandAll. Let me post my code here so that we have a base for further discussion.

                          My JSF page looks like this:

                          <ui:define name="body">
                          
                           <h:form>
                           <a:jsFunction name="bodyOnload" actionListener="#{treeController.expandTree}" reRender="businessTree" />
                           </h:form>
                          
                           <h:messages globalOnly="true" styleClass="message" id="globalMessages"/>
                          
                           <h:form>
                           <rich:tree id="businessTree"
                           binding="#{treeController.tree}"
                           switchType="ajax"
                           value="#{businessTree}"
                           var="business"
                           style="margin: 10px; width: 300px;"
                           nodeFace="simpleNode">
                           <rich:treeNode type="simpleNode">
                           <h:outputText value="#{business.name}"/>
                           </rich:treeNode>
                           </rich:tree>
                           </h:form>
                          
                          </ui:define>
                          


                          The JavaScript function bodyOnload() is called from the facelet template where the HTML body tag is declared:
                          <body onload="bodyOnload()">


                          The server side code is a Seam component:
                          @Name("treeController")
                          public class TreeController {
                          
                           private HtmlTree tree;
                          
                           public HtmlTree getTree() {
                           return tree;
                           }
                          
                           public void setTree(HtmlTree tree) {
                           this.tree = tree;
                           }
                          
                           // Called on JSF on body onload to expand the business tree to the selected business
                           public void expandTree() {
                           try {
                           tree.queueExpandAll();
                           } catch (IOException e1) {
                           e1.printStackTrace();
                           }
                           }
                          }
                          


                          • 10. Re: rich:tree - programatically set the selected node and ex
                            kingcu

                            However, now I got stuck with two things:

                            1. Programmatically traverse the tree starting from the root, because I need to compare each node with the previously user selected business to determine the exact expansion point; it seems getTreeNode() only returns the selected node, to me there should be another API getTreeRoot() that returns the root node of the tree.

                            2. Programmatically select a given tree node, because I want the expanded tree node to be automatically selected after expansion. I don't see any API existing that allows me to accomplish this. There is a isSelected() to determine if the node is selected, but no corresponding setSelected().

                            IMO, there should be an API corresponding to each user action that occurs on the tree, like: expand, collapse, select, etc.

                            Max: I would be interested to see how you determine the specific expansion point in the tree.

                            • 11. Re: rich:tree - programatically set the selected node and ex
                              max76

                              Hi!

                              1st: every treenode has an unique id -- this id is later used to identify the node which gets expanded... see TreeNode.addChild(java.lang.Object identifier, TreeNode child); in my case the id is simply an Integer which gets incremented when i add a node.

                              2nd: my treemodel class has a reference to the rootnode; and with this rootnode i can reach every node in my tree via treenode.getChildren()

                              3rd: my treemodel has a reference to the HtmlTree

                              So the expand all action looks like (as mentioned by kingcu):

                               public String expandAll() {
                               System.out.println("expandAll");
                              
                               HtmlTree hTree = (HtmlTree) tree;
                               try {
                               hTree.queueExpandAll();
                               } catch (IOException e1) {
                               e1.printStackTrace();
                               }
                              
                               return null;
                               }
                              


                              If i want to expand to a given node i must expand every parentcontainer on the way to the node...

                              If my tree looks like A-B-C-D where D is a leave an i want to expand the node D one must expand node A, node B, and node C ... thats what i mean with queue expansion of parents... and this is done via ((HtmlTree) tree).queueNodeExpand(RowKey);

                              The RowKey describes the Path to the node...

                              this is done via following action:

                              nodeId is a property of my treemodel with the ID of the node that should be expanded...

                              getNode(nodeID) is an utility method that traverses the tree and returns the node object with the given id.

                              path is an list of IDs of the parents (in my example A, A-B, A-B-C)

                               public String expandNode() {
                               Node node = getNode(nodeId);
                               ArrayList<Integer> path = new ArrayList<Integer>();
                               while (node != null) {
                               path.add(node.getId());
                               node = (Node) node.getParent();
                               }
                               Collections.reverse(path);
                               path.remove(0); // dont expand rootnode, it is not displayed
                              
                               for (int i = 0; i < path.size(); i++) {
                               ArrayList<Integer> list = new ArrayList<Integer>();
                               for (int n = 0; n <= i; n++) {
                               list.add(path.get(n));
                               }
                              
                               ListRowKey key = new ListRowKey(list);
                               try {
                               ((HtmlTree) tree).queueNodeExpand(key);
                               } catch (IOException e) {
                               e.printStackTrace();
                               }
                               }
                              
                               return null;
                               }
                              



                              hope that helps...


                              • 12. Re: rich:tree - programatically set the selected node and ex
                                vh

                                This is great. But I didn't see it mention how to select a node.
                                Can you help?

                                • 13. Re: rich:tree - programatically set the selected node and ex
                                  mheidt

                                  vh,

                                  I enhanced the code by the following:

                                  TreeState ts = (TreeState)tree.getComponentState();


                                  and at the end

                                  if (key!=null){
                                   ts.setSelected(key);
                                   this.setSelectedNode((ComponentSetNode)tree.getRowData(key)); //optional
                                  }




                                  • 14. Re: rich:tree - programatically set the selected node and ex
                                    blabno

                                    Actually your code does not work for me.
                                    I use following instead :

                                     List<Object> path = new ArrayList<Object>();
                                     while (node != null) {
                                     path.add(((MyTreeNodeImpl) node).getId());
                                     node = node.getParent();
                                     }
                                     Collections.reverse(path);
                                     path.remove(0); // dont expand rootnode, it is not displayed
                                    
                                     TreeState state = (TreeState) tree.getComponentState();
                                    
                                     for (int i = 0; i < path.size(); i++) {
                                     List<Object> list = new ArrayList<Object>();
                                     for (int n = 0; n <= i; n++) {
                                     list.add(path.get(n));
                                     }
                                    
                                     ListRowKey key = new ListRowKey(list);
                                     try {
                                     state.expandNode(tree, key);
                                     } catch (IOException e) {
                                     log.error(e);
                                     }
                                     }
                                     ListRowKey key = new ListRowKey(path);
                                     state.setSelected(key);
                                    


                                    Note that I do not use
                                    ((HtmlTree) tree).queueNodeExpand(key);

                                    but instead i use
                                    state.expandNode(tree, key);


                                    1 2 Previous Next