7 Replies Latest reply on Mar 27, 2007 7:34 AM by Vaclav Balak

    Changes to the tree node are not reflected during ajax

    Andrew Apprentice

      I am trying to research the feasibility of using the tree for our needs (See http://tinyurl.com/25v9wl for more information). I created a custom tree node that changes it's children based on node selection. The tree is not reflecting any changes to the tree node hierarchy in my backing bean

      XHTML:

      <a4j:form id="testForm">
       <rf:tree
       id="testTree"
       var="_data"
       switchType="ajax"
       ajaxSubmitSelection="true"
       preserveModel="none"
       value="#{ajaxTreeTest.rootNode}"
       nodeSelectListener="#{ajaxTreeTest.onTreeNodeSelection}"
       nodeFace="#{_data eq 'PagedTreeNode.movePrevious' ? 'movePrevNode' :
       (_data eq 'PagedTreeNode.moveNext' ? 'moveNextNode' : 'node' )}">
       <rf:treeNode type="movePrevNode">
       ^ Previous
       </rf:treeNode>
       <rf:treeNode type="node">
       #{_data}
       Num selections: #{ajaxTreeTest.numSelections}
       </rf:treeNode>
       <rf:treeNode type="moveNextNode">
       V Next
       </rf:treeNode>
       </rf:tree>
       </a4j:form>
      


      Inside the "ajaxTreeTest.onTreeNodeSelection" I modify the node:
       public void onTreeNodeSelection(NodeSelectedEvent evt)
       {
       log.info("Selected event: " + evt);
       HtmlTree tree = (HtmlTree)evt.getComponent();
       TreeRowKey key = (TreeRowKey)tree.getRowKey();
       log.info("Key: " + key);
       TreeNode node = rootNode;
      
       if (PagedTreeNode.MOVE_NEXT_ID.equals(tree.getRowData()) ||
       PagedTreeNode.MOVE_PREV_ID.equals(tree.getRowData()))
       {
       for (Iterator iter = key.iterator(); iter.hasNext();)
       {
       Object id = iter.next();
       log.info("ID: " + id);
       node = node.getChild(id);
       log.info("Node: " + node);
       }
      
       if (PagedTreeNode.MOVE_NEXT_ID.equals(node.getData()))
       {
       PagedTreeNode parentNode = (PagedTreeNode)node.getParent();
       parentNode.setStartAt(parentNode.getStartAt() + parentNode.getPageSize());
       log.info("New start at: " + parentNode.getStartAt());
       }
       else if (PagedTreeNode.MOVE_PREV_ID.equals(node.getData()))
       {
       PagedTreeNode parentNode = (PagedTreeNode)node.getParent();
       parentNode.setStartAt(parentNode.getStartAt() - parentNode.getPageSize());
       log.info("New start at: " + parentNode.getStartAt());
       }
       }
       }
      


      Log output:
      17:15:25,535 INFO [TestAjaxTree] Selected event: org.richfaces.component.events.AjaxSelectedEvent[source=org.richfaces.component.html.HtmlTree@2a821]
      17:15:25,536 INFO [TestAjaxTree] Key: PagedTreeNode.moveNext
      17:15:25,536 INFO [TestAjaxTree] ID: PagedTreeNode.moveNext
      17:15:25,536 INFO [TestAjaxTree] Node: org.richfaces.component.TreeNodeImpl@6c4a07
      17:15:25,537 INFO [TestAjaxTree] New start at: 20
      


      When I refresh the page, the tree is correct. I was hoping that the tree renderer would automatically detect that some nodes were removed and some were added (by their IDs), but that was not the case. Is there any way in the AJAX rendering model to flag the nodes as dirty so that they get updated?



        • 1. Re: Changes to the tree node are not reflected during ajax
          Andrew Apprentice

          I got this fixed. I found the UITree.getAjaxKeys()/setAjaxKeys() methods and tried them out. I just needed to add the ListRowKey of the parent node to this set (and create it if it didn't already exist) to be able to re-render the children

          • 2. Re: Changes to the tree node are not reflected during ajax
            Andrew Apprentice

            I am still having some difficulties. When I need to update child nodes, it is fine, since there is a parent node that I can add to the ajax keys of the tree. However, I can't seem to be able to refresh the entire tree if I need to refresh all the nodes under the root node. I tried:

            AjaxContext.getCurrentInstance().addComponentToAjaxRender(tree);

            What I ended up with is all the old nodes plus the new nodes on the page, and the new nodes don't react to mouse over events, so it seems they were not properly initialized.

            I haven't been able to find the method that triggers the different behavior of encoding on the first time vs. an AJAX rendering.

            How can I force the tree to fully re-render and re-initialize any javascript that it requires from within the node selection listener instead of just using the AJAX "diff" style of renderering?

            Or better yet, how can I tell it to just re-render the root. The following doesn't work:
            tree.getAjaxKeys().add(new ListRowKey(""));


            • 3. Re: Changes to the tree node are not reflected during ajax
              Andrew Apprentice

              Well, I found a work-around, but it is extremely ugly. What is happening, is that an AjaxEvent being wrapped in an IndexedEvent is getting added by the HtmlTreeNode and storing the TreeRowKey. During rendering, the AjaxViewRoot broadcasts this event, setting the tree's client ID to that of the node. As a result, the tree only renders node DIVs and not the tree DIV.

              Here is the ugly work around contained in the node selection listener:

              HtmlTree tree = (HtmlTree)nodeSelectedEvent.getComponent();
              // Make sure the tree is re-rendered
              AjaxContext.getCurrentInstance().addComponentToAjaxRender(tree);
              
              TreeRowKey key = (TreeRowKey)tree.getRowKey();
              // Clear the tree's client ID
              // 1) clear the row key
              tree.setRowKey(null);
              // 2) queue an event so that the key will be cleared right
              // before rendering
              tree.queueEvent(new AjaxEvent(tree.getNodeFacet()));
              // 3) reset the row key
              tree.setRowKey(key);
              


              It works, but I really do hate it. There has got to be a better way of doing this unless it is a bug. Perhaps the tree renderer should check the queued rendered regions, and if the tree's base client ID is in that list, then reset the client ID to the base client ID instead of the client ID for the row. Any help?

              • 5. Re: Changes to the tree node are not reflected during ajax
                Vaclav Balak Newbie

                Doesn't work for me :-(.

                <rich:tree value="#{SessionBean.fileTree}" actionListener="#{item.onTreeNodeSelection}" var="item" nodeFace="directory" switchType="ajax" id="fileTree">
                 <rich:treeNode type="directory">
                 <a4j:commandLink value="#{item.dirName}" action="#{SessionBean.treeNodeClicked}">
                 <a4j:support event="onclick" reRender="fileTree" actionListener="#{item.nodeClicked}"/>
                 </a4j:commandLink>
                 </rich:treeNode>
                </rich:tree>
                


                When action of commandLink is called (which creates new children), new child is created, but tree is rendered twice and half of components doesnt work as expected.
                Can you be more concrete about your solution, please?

                • 6. Re: Changes to the tree node are not reflected during ajax
                  Adrian Mitev Master

                  Why do you nest a4j:support in a4j:commandLink?

                  • 7. Re: Changes to the tree node are not reflected during ajax
                    Vaclav Balak Newbie

                    because of the onclick event in a4j:support - commandLink is visible tree node, so i need action for it (item.nodeClicked) and for whole application (SessionBean.treeNodeClicked). Or I understood it bad?