Monday, April 11, 2011

Dynamic Menus in RichFaces

RichFaces has no built-in functionality for creating dynamic menus, the reason for this could be that a lot of different use case scenarios require different type of dynamic menus. This example presents the most simple case: The menu items are dynamically populated from a list, and an action method is called with the id of the menu item, when the user selects the menu item.

The data of a menu item is represented by the MenuItem class:

public class MenuItem {

 /**
  * Id of the menu item
  */
 private int id;

 /**
  * Label for menu item
  */
 private String label;

 /**
  * Constructor
  * 
  * @param label The label fo the menu item
  * @param id the id of the menu item
  */
 public MenuItem(String label, int id) {
  super();
  this.label = label;
  this.id = id;
 }

 /**
  * @return the id
  */
 public int getId() {
  return this.id;
 }

 /**
  * @return the label
  */
 public String getLabel() {
  return this.label;
 }

 /**
  * @param id
  *            the id to set
  */
 public void setId(int id) {
  this.id = id;
 }

 /**
  * @param label
  *            the label to set
  */
 public void setLabel(String label) {
  this.label = label;
 }

 /**
  * @see java.lang.Object#toString()
  */
 @Override
 public String toString() {
  StringBuilder builder = new StringBuilder();
  builder.append("MenuItem [id=");
  builder.append(this.id);
  builder.append(", label=");
  builder.append(this.label);
  builder.append("]");
  return builder.toString();
 }

}


The dynamic menu is supported by the DynamicMenu class. It provides the list of menu items and an action method:

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.jboss.seam.annotations.Name;

@Name("dynMenu")
public class DynamicMenu {
 
 private Logger log = Logger.getLogger(DynamicMenu.class.getName());

 /**
  * Example action method
  * 
  * @param id the menu item id
  */
 public void action(int id) {
  log.info("Action called with menu item id: " + id);
 }

 /**
  * Returns the list of menu items.
  * 
  * @return the list of menu items
  */
 public List getMenuItems() {

  List menuItems = new ArrayList();

  menuItems.add(new MenuItem("Menu Item #1", 1));
  menuItems.add(new MenuItem("Menu Item #2", 2));
  menuItems.add(new MenuItem("Menu Item #3", 3));

  return menuItems;
 }
}


The following code snippet contains the dynamic menu xhtml example. The key in the dynamic menu items is the <c:forEach> iterator. The namespace declaration is very important, it should be xmlns:c="http://java.sun.com/jstl/core". If you use xmlns:c="http://java.sun.com/jsp/jstl/core" namespace, the iterator won't work!

<h:form xmlns:h="http://java.sun.com/jsf/html">

...

   <rich:dropDownMenu
    value="Dynamic Menu Item Example"
    style="text-decoration: none;"
   >


    <c:forEach xmlns:c="http://java.sun.com/jstl/core"
     var="item"
     items="#{dynMenu.getMenuItems()}"
    >

     <rich:menuItem
      id="menuItem#{item.id}"
      submitMode="ajax"
      value="#{item.label}"
      action="#{dynMenu.action(item.id)}"
     >

     </rich:menuItem>
    </c:forEach>



   </rich:dropDownMenu>

...

</h:form>

6 comments:

  1. this is only one level menu, how about multiple level?

    ReplyDelete
    Replies
    1. I think for multiple level submenus, some kind of AJAX enabled solution could be the key. The simple case when you have fixed number of leveles. In this case you just embed the necessary number of c:forEach-es. If you want to display "unlimited" number of hierarchical menu items, a more sophisticated solution would be to use JavaScript to retrieve menu item data from the server and dynamically generate the html elements on the fly, basically you would need to create your own JSF menu tag...

      Delete
  2. tried but didn't work.

    ReplyDelete
  3. You can use "binding" attribute of a JSF RichFaces (or another framework) component to build a dynamic menu.

    Example:
    JSF File:



    Managed Bean (Session Scoped):
    1. declare attribute:
    private UIToolbar myMenu;

    2. build it on login() action, for example:
    UIDropDownMenu ddm = new UIDropDownMenu();
    ddm.setLabel("Teste123333");
    UIDropDownMenu ddm2 = new UIDropDownMenu();
    ddm2.setLabel("Teste1233333333333333");

    menu = new UIToolbar();
    menu.getChildren().add(ddm); menu.getChildren().add(ddm2);


    You can add submenus as well. Please, verify the class hierarchy of JSF "UIComponent" class.

    Hope this helps

    ReplyDelete
  4. Please, forget what I said.

    Consider this:
    https://community.jboss.org/thread/167368

    ReplyDelete