7 Replies Latest reply on Apr 20, 2015 2:07 PM by przemeck

    RF4 rich:tree selecting and expanding nodes programatically

    garagoth

      Hello,

       

      In RF3 there were tree state advisors that elt me select and expand nodes programatically.

      In RF4 I found only treeNode.expanded attribute - but I found no way to SELECT a node programatically.

      Could anyone help me with this?

       

      Regards,

      Marcin.

        • 1. Re: RF4 rich:tree selecting and expanding nodes programatically
          ilya40umov

          Hi,

           

          I think the answer is partially present here(advisors are replaced with attributes):

          https://community.jboss.org/wiki/RichFacesMigrationGuide33x-4xMigration-ComponentsMigration-RichTreeComponents

           

          I think you can try to use the JSF binding in order to get the tree state on the server side and change it in JSF beans.

           

          You can find some more info in this thread: https://community.jboss.org/message/609279

          • 2. Re: RF4 rich:tree selecting and expanding nodes programatically
            garagoth

            Hi,

             

            Well, there is info about expanding nodes only and expanded attribute, true.

            Still nothing about selecting nodes...

             

            M.

            • 4. Re: RF4 rich:tree selecting and expanding nodes programatically
              garagoth

              Ilya,

               

              Thanks for links. I tried getSelection() first - just to see what it returns.

              Aaand... why does it return Collection<Object> if everytime that Object is in fact SequenceRowKey ?

               

              And while testing that methods, I found that using binding with any listener added to component in xhtml document adds that listener every time. So after 4 page refreshes, listener is called 5 times. Why is that?

              Also, what is the difference between toggleListener and selectionChangeListener ? (on a side note, they have errors in ocumentation. They mention wrong events.) I could not figure out when toggleListener is being called. Seems to me that almost randomly. EDIT: On, toggleListener with toggleMode=client CAN work strange, I admit. My fault. And now difference is obvious as well...

              (Why there is no simple method to react on tree node selection, knowing exactly what was selected?)

               

              Ok, enough of my frustrations - back to drawing board.

              If anyone knows answers to above, do not hesitiate to make then lenghty.

               

              Regards,

              Marcin.

              • 5. Re: RF4 rich:tree selecting and expanding nodes programatically
                garagoth

                Hi,

                 

                Another day of testing. Results are rather disappionting....

                 

                1. selection attribute (or get/setSelection() via binding of UITree) - it HAS to be a collection of node keys, starting from root to node that you want to select. Whole path that is. I could live with this (not very intuitive tho), just one question to this: is there any way to get a parent node of any given node from tree? And then to get key of that node?

                It required me to add selectionChangeListener (to track user changes) and selection attribute (via a tree binding in my case) to

                 

                2. expanding nodes. Oh man... All with toggleType = "ajax"

                2.1 with a toggleListener and a4j:status it breaks. Upon a click on a [+] sign, status popup appears, tree expands as expacted... but status popup NEVER finishes. On selectionChange it works fine with status popup...

                And while we are on this, how to start status popus only for selectionChange, and not for toggle?

                <a4j:ajax event="beforeselectionchange" status="statusStatus"/> does not work, it causes selectionListener being NOT invoket at all.

                 

                2.2 toggleListener and expanded attribute that leads to a method ( <rich:treeNode expanded="#{sessionBean.isNodeExpanded(row)}" ... /> )

                Logic is as following: toggleListener gets invoked, it marks a state of expanded/collapsed node in session bean (in a Map<Node, Boolean>), and isNodeExpanded(Node node) returns recorded value (or false if unknown node)

                Reality:

                First, isNodeExpanded(node) gets called. Then, a toggleListener() gets called. The end.

                In result, treeNode does not expand/collapse. It does that on next tree rerender, whenever that happens. Immediate attribute changes nothing.

                I found elsewhere on this forum that expanded attribute takes a setter/getter pair, but that would have to be an attribute on node itself - and in my scenario, where tree is application-scoped (and shared between many users of application), is impossible (I cannot expand tree for other users...)

                 

                In the end, I'm in a dead-end now. Could anyone shed some light on this please? Maybe I'm doing something in a very wrong way.

                 

                Regards,

                Marcin.

                 

                P.S.

                Richfaces 4.2.2.Final and 4.3.0.M1 behave the same.

                • 6. Re: RF4 rich:tree selecting and expanding nodes programatically
                  garagoth

                  Heh. I figured it (see point 2.2 above) out, but authors of Tree implementation may not like this...

                   

                  So, expanding tree nodes...

                  First, a tree binding in session bean is required and a Map of expandedn nodes.

                  Then, expanded attribute (why it is in treeNode, not tree? Repeating it in every treeNode is... well, silly?) points to a getter/setter pair in session bean. Currently rendered treNode is fetched using tree binding.

                  It looks like this:

                   

                  {code:java}

                  private UITree treeBinding;

                  private Map<TreeNode, Boolean> toggleState = new HashMap<TreeNode, Boolean>();

                   

                  (... getter and setter for binding ...)

                   

                  public void setTreeNodeExpanded(boolean expanded)

                  {

                          TreeNode node = (TreeNode) treeBinding.getRowData(); // Notice this line

                          toggleState.put(node, expanded);

                  }

                   

                  public boolean getTreeNodeExpanded()

                  {

                          TreeNode node = (TreeNode) treeBinding.getRowData(); // Notice this line

                   

                          if(toggleState.containsKey(node))

                              return toggleState.get(node);

                          return false;

                  }

                   

                  // And a method to expand/collapse any node programatically

                  public void setToggeStateForNode(TreeNode node, boolean expanded)

                  {

                        toggleState.put(node, expanded);

                  }

                  {code}

                   

                  {code:xml}

                  <rich:tree toggleType="ajax" binding="#{sessionBean.treeBinding}">

                          <rich:treeNode expanded="#{sessionBean.treeNodeExpanded}"/>

                  </rich:tree>

                  {code}

                   

                  Anyone with a beter way?

                   

                  I still haven't figured out how to solve rest of my tree problems.

                   

                  Regards,

                  Marcin.

                  • 7. Re: RF4 rich:tree selecting and expanding nodes programatically
                    przemeck

                    In RichFaces 4.5.4 instead of binding the tree I used binding of selection <rich:tree selection="#{treeBean.selection}">

                     

                    @ManagedBean

                    @ViewScoped

                    public class TreeBean implements Serializable {

                      private Collection<Object> selection;

                     

                      public Collection<Object> getSelection() {

                      return selection;

                      }

                     

                      public void setSelection(Collection<Object> selection) {

                      this.selection = selection;

                      }

                    }

                     

                    Now let's say you've built your tree model with string node keys:

                     

                    [-] 'grandaprentKey0'

                    [+] 'grandparentKey1'

                      [+] 'parentKey0'

                        [-] 'childKey0'

                        [-] 'childKey1'

                        [-] 'childKey2' <- Node to be selected

                    [-] grandparentKey2

                     

                    To select desired node you may invoke:

                     

                        Collection<Object> mySelection = new ArrayList();

                        mySelection.add(new SequenceRowKey("grandparentKey1", "parentKey0", "childKey2"));

                        treeBean.setSelection(mySelection);

                     

                    To reflect this selection change in view you also have to expand the whole path. I made it by binding tree node's "expanded" attribute.

                     

                    The working example (selections, expansions) is here:

                     

                        http://en.mobilne.org/2015/04/interactions-with-richtree.html

                     

                    ______________________

                     

                    @garagoth, to answer the question about getting parent of the tree node You'd need to have got somehow it's SequenceRowKey and then use sequenceRowKey.getParent();

                    Then, having root node You are able to iterate over contents of resulting parent sequenceRowKey['grandparentKey1', 'parentKey0'] and

                    get the parent node instance using rootNode.getChild("grandparentKey1").getChild("parentKey0");

                     

                    Anyone knows about other possibilities?