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

    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:

      {code}<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>{code}

      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:

      {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;

      }{code}

      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:

       

      {code}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{code}

      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.

            {code:xml}

            <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>

            {code}

             

            try with

             

             

            {code:xml}

            <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>

            {code}

             

             

            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