11 Replies Latest reply on Mar 18, 2008 6:30 AM by carlhowarth

    Dynamic Context Menu

      Hi,

      Is it possible to dynamically generate the content of a context menu? I have a data table displaying data of, say, 'X' objects. 'X' objects can have a number of child 'Y' objects and I would like the context menu to provide me with links to the various 'Y' objects... I've tried passing in my collection to the menu like this:

      <rich:componentControl event="onclick" for="menuofy" operation="show">
       <f:param value="#{x.collectionOfYs}" name="collectionOfYs"/>
       </rich:componentControl>


      And then using a repeater to generate the links in the menu:

      <rich:contextMenu attached="false" id="menuofy">
       <a4j:repeat value="#{collectionOfYs}">
       <rich:menuItem>
       <t:commandLink action="#{goto Y action}" value="#{collectionOfYs.y.description}"/>
       </rich:menuItem>
       </a4j:repeat>
      </rich:contextMenu>


      This just gives me a 'Error in conversion Java Object to JavaScript'.

      I am new to this control so think I've probably approached it in completely the wrong manner! Can anybody tell me if what I am trying to do is achievable and if so how best to do it?

      Thanks, Carl

        • 1. Re: Dynamic Context Menu

          The repeater in my example is incorrect and should have read:

           <a4j:repeat value="#{collectionOfYs}" var="y">
           <rich:menuItem>
           <t:commandLink action="#{goto Y action}" value="#{y.description}"/>
           </rich:menuItem>
           </a4j:repeat>
          



          • 2. Re: Dynamic Context Menu
            henady

            use facelets ui:forEach instead of a4j:repeat, it works normally. If you're using JSP, read richfaces FAQ - a4j:repeat will not work for contextmenu.

            • 3. Re: Dynamic Context Menu

              I'm afraid we're not using facelets so that is out of the question for us.

              Can anybody think of another way to achieve this using the provided menu please?

              Thanks in advance, Carl

              • 4. Re: Dynamic Context Menu
                henady

                Read a solution in richfaces FAQ.

                • 5. Re: Dynamic Context Menu

                  I'm sorry, I can't see a FAQ that offers me any help with this. Please could you point me in the correct direction?

                  • 7. Re: Dynamic Context Menu

                    Thanks for that -

                    I am comfortable with creating dynamic drop down menus on the fly but can't see how I would create a different menu for each row that is generated on my datatable.

                    Am I missing something really simple here?

                    Thanks, Carl

                    • 8. Re: Dynamic Context Menu

                      Hello - I'm just coming back to this but still without joy. Can anybody tell me if it is possible to dynamically create the content of a context menu so that it is different per row on a datatable?

                      Thanks! Carl

                      • 9. Re: Dynamic Context Menu
                        fabmars

                        Use ilya_shaikovsky's advice to create your own component on the fly. Not only the menu because you wouldn't know where to look for the data to make it.

                        You have to make the Table and the menus all programatically. That's not so hard. That's like making swing components. The following example was made on the fly and untested. That's to give you an idea on how to do.

                        ExpressionFactory expFactory = FacesContext.getCurrentInstance().getApplication().getExpressionFactory();
                        
                        HtmlDataTable table = new HtmlDataTable();
                        HtmlColumn col = new
                        table.getChildren().add(col);
                        //add your facets if you want
                        for(Y y : ys) {
                         HtmlOutputText text = new HtmlOutputText();
                         text.setValue(y.getLabel());
                         col.getChildren().add(text);
                        
                         HtmlContextMenu context = new HtmlContextMenu();
                         context.setEvent("oncontextmenu");
                         text.getChildren().add(context);
                        
                         for(X x : y.getListOfXs) {
                         HtmlMenuItem item = new HtmlMenuItem();
                         item.setValue(x.getLabel());
                         context.getChildren().add(item);
                        
                         MethodExpression actionExpr = expFactory.createMethodExpression(FacesContext.getCurrentInstance().getELContext(), "#{myBean.myAction}", null, new Class[]{});
                         item.setActionExpression(actionExpr);
                         }
                        }
                        


                        Then make this component available with some getter of some bean (the setter has to be here but can remain empty) and bind it to some "fake" component like
                        <h:dataTable binding=#{myBean.myComponent}/>.
                        


                        Obviously you wanna go to some differnet page depending on what menu you're clicking on, or at least load the Y entity whose menu you clicked on and display it. For that, you can do several ways:

                        - add the java equivalent of f:actionParam as a child of the menu item, where some property of some bean underneath or destination page is going to be set and load your entity.

                        - set the data attribute of your item, and define an actionListener on it in addition to the action. The actionListener will be triggered first and by calling ((HtmlMenuItem)event.getParent()).getData() you will retried your Y and put it somewhere accessible on the following page. The action called just after will enable you to trigger some navigation rule. Adding an actionListener programacically is almost as easy as an action.

                         MethodExpression listenerExpr = expFactory.createMethodExpression(FacesContext.getCurrentInstance().getELContext(), "#{myBean.myActionListener}", null, new Class[]{ActionEvent.class});
                         item.addActionListener(new MethodExpressionActionListener(listenerExpr));
                         item.setAjaxSingle(true);
                        


                        I hope this helps

                        • 10. Re: Dynamic Context Menu

                          Hello there,

                          Thanks very much for your detailed answer - it's much appreciated.

                          The only thing I am having trouble with is knowing how to access the collection used in the for loop. This collection will differ for each row that is displayed in the table, and therefore the content and the size of the menu should differ too (albeit the actions will be the same).

                          Hopefully this makes sense, and thanks again for your help so far.

                          Carl

                          • 11. Re: Dynamic Context Menu

                            Apologies for pestering, but I'm still having troubles with this - if anyone can help further that'd be fantastic!

                            Cheers, Carl