3 Replies Latest reply: May 3, 2013 6:27 AM by Alexander Scheffler RSS

    Creating a dynamic context menu dependent on the <rich:tree> selection

    Karsten Wutzke Expert

      Hello,

       

      I have a tree on a page to which I'd like to attach a dynamic context menu depending on the name of the node and its type:

      <h:form id="tree-form">
        <rich:panel header="Sort Tree">
          <rich:tree value="#{nodeManager.rootTreeNode}"
                     var="treeNode"
                     nodeType="#{treeNode.type}"
                     toggleType="client"
                     selectionType="ajax"
                     selectionChangeListener="#{nodeManager.selectionChanged}"
                     id="document-tree">
              
            <rich:treeNode type="root" id="root-node">
              ...
            </rich:treeNode>
        
            <rich:treeNode type="chapter" id="chapter-node">
              ...
            </rich:treeNode>
            
            ...
            
          </rich:tree>
            
          <rich:contextMenu target="document-tree" mode="ajax">
            <rich:menuItem label="Add chapter to #{nodeManager.selectedNode.name}..." />
            <rich:menuItem label="Remove #{nodeManager.selectedNode.name}..."
                           rendered="#{nodeManager.selectedNodeClassName eq 'ChapterNode'}" />
          </rich:contextMenu>
      
        </rich:panel>
      </h:form>

       

      NodeManager is a view-scoped bean, which successfully receives the selection changes when the node is left- or right-clicked. It also overwrites the selected node in that bean from which getSelectedNode() returns the instance and getSelectedNodeClassName() returns the simple class name, here "RootNode" or "ChapterNode".

       

      What I want now is a dynamic context menu: roots cannot be deleted (no REMOVE shown), new chapters can only be added to roots or chapters (ADD always shown).

       

      RootNode shall show menu:

       

      * Add chapter to [node name]...

       

      ChapterNode shall show menu:

       

      * Add chapter to [node name]...

      * Remove [node name]...

       

      Here's the relevant NodeManager code:

      public void selectionChanged(TreeSelectionChangeEvent event)
      {
          log.info("Tree selection!");
              
          List<Object> selection = new ArrayList<Object>(event.getNewSelection());
          Object currentSelectionKey = selection.get(0);
          
          UITree tree = (UITree)event.getSource();
          Object storedKey = tree.getRowKey();
          tree.setRowKey(currentSelectionKey);
          selectedContainerTreeNode = (ContainerTreeNode)tree.getRowData();
          tree.setRowKey(storedKey);
          
          log.info("Selected node = " + selectedContainerTreeNode.getName());
      }
      
      public Node getSelectedNode()
      {
          return selectedContainerTreeNode != null ? selectedContainerTreeNode.getNode() : null;
      }
      
      public String getSelectedNodeClassName()
      {
          String className = selectedContainerTreeNode != null ? selectedContainerTreeNode.getNode().getClass().getSimpleName() : null;
          
          log.info("Selected node class name = " + className);
          
          return className;
      }

       

      However, the dynamically set selected node and its class name returned are always null, as #{nodeManager.selectedNode.name} renders nothing (empty string?) and the rendered="#{nodeManager.selectedNodeClassName eq 'ChapterNode'}" *always* seems to evaluate to false, even though the selectionChanged listener clearly prints to the console that a new tree node has successfully been set:

       

      12:27:20,662 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node class name = null
      12:27:26,082 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node class name = null
      12:27:26,083 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Tree selection!
      12:27:26,083 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node = wwwwwwwwww
      12:27:26,145 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node class name = RootNode
      12:27:26,177 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node class name = RootNode
      12:27:26,307 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node class name = RootNode
      12:27:27,368 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node class name = RootNode
      12:27:27,369 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Tree selection!
      12:27:27,369 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node = subb
      12:27:27,427 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node class name = ChapterNode
      12:27:27,463 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node class name = ChapterNode
      12:27:27,581 INFO  [com.company.project.facade.NodeManager] (http-localhost-127.0.0.1-8080-3) Selected node class name = ChapterNode

       

      What's wrong with the above approach? How do you fix this?

       

      Karsten

        • 1. Re: Creating a dynamic context menu dependent on the <rich:tree> selection
          garagoth Newbie

          This is because your contextMenu is rendering at the same time when tree is rendering for the forst time on your page.

          Unless you re-render context menu, it will show initial content every time.

           

          I am also struggling with this, and so far I have no solution when to re-render context menu. Simply adding rerender="contextMenuId" to a tree causes menu to appear for a moment and then disappear.

           

          M.

          • 2. Re: Creating a dynamic context menu dependent on the <rich:tree> selection
            Greg C Newbie

            Have you tried wrapping the context menu in an outputPanel?

            I suspect..(haven't tried the code that was given).

            That the context menu may get rendered initially...but then is lost from the page.

            <rich:contextMenu target="document-tree" mode="ajax">
                  <rich:menuItem label="Add chapter to #{nodeManager.selectedNode.name}..." />       <rich:menuItem label="Remove #{nodeManager.selectedNode.name}..."                     rendered="#{nodeManager.selectedNodeClassName eq 'ChapterNode'}" />    </rich:contextMenu>
            

             

             

            try with

             

            <a4j:outputPanel id="myContextMenuPanel_Id" > 
              <rich:contextMenu target="document-tree" mode="ajax">      <rich:menuItem label="Add chapter to #{nodeManager.selectedNode.name}..." />      <rich:menuItem label="Remove #{nodeManager.selectedNode.name}..."                     rendered="#{nodeManager.selectedNodeClassName eq 'ChapterNode'}" />    </rich:contextMenu>
            </a4j:outputPanel>
            

             

             

             

            But don't forget to add the panel as a target for rendering on the tree....

             

            Wrapping them is how I do mine..and I haven't had a problem with it...

             

            - Sorry about the formatting...I'm not great with the wiki markup.

            • 3. Re: Creating a dynamic context menu dependent on the <rich:tree> selection
              Alexander Scheffler Newbie

              I have the same problem. We solved it with richfaces 3.3 but now we want to migrate to richfaces 4.3.1.Final and I am not able to wangle this again...

              With Richfaces 3.3 our tree looks like the following:

               

              {noformat}

              <rich:tree

                  switchType="ajax"

                  nodeSelectListener="#{someBean.processNodeSelect}"

                  adviseNodeOpened="#{someBean.isAdviseNodeOpened}"

                  value="#{someBean.treeNode}"

                  var="item"

                  treeNodeVar="nodeItem"

                  reRender="..."

                  ajaxSubmitSelection="true"

                  id="treeView"

                  >

                  <rich:treeNode

                      id="TreeElement">

               

                      <h:outputText value="#{item.displayName}" />

               

                      <a4j:support

                          event="oncontextmenu"

                          disableDefault="true"

                          oncomplete="#{rich:component('contextmenu')}.doShow(event, {})"

                          reRender="documentContextMenu"

                          status="globalStatus">

                          <a4j:actionparam

                              value="#{item.id}"

                              name="treeNodeItem"

                              assignTo="#{someBean.menuSelectedNodeId}"

                              actionListener="#{someBean.processCreateContextMenu}" />

                      </a4j:support>

                  </rich:treeNode>

              </rich:tree>

              {noformat}

               

              and the contextmenu looks like

               

              {noformat}

              <a4j:outputPanel

                  layout="inline"

                  id="documentContextMenu">

                   <rich:contextMenu

                       disableDefaultMenu="true"

                       attached="false"

                       id="contextmenu"

                       binding="#{someBean.contextMenu}"

                       submitMode="ajax">

                      <a4j:support

                          event="onclick"

                          reRender="..."

                          status="globalStatus">

                      </a4j:support>

                   </rich:contextMenu>

              </a4j:outputPanel>

              {noformat}

               

              I wonder, is there any chance to rebuild this in richfaces 4? Now or in the future?

               

               

              Thanks

              Alex