Keeping rich:panelMenu state

This example is in response to this post.

The solution uses two managed beans, one in request and one in session scope. The session bean will keep the menu state. You can easily extend this example to use Seam. I need to remember two things. First is which group was opened/closed and second which item inside the group was clicked. Remembering which item inside the group was clicked is done via selectedChild=”#{menuState.selectedMenuItem}”. Remembering which group was opened is done via value attribute on each group. The value is saved automatically.

I’m setting action=”page.xhtml” because I’m using a custom navigation handler. Standard navigation rules will work the same way.

start.xhtml:



  
	
	
	
   
   
       
	
	
   


MenuBean managed bean (in request scope):


package test;

import javax.faces.event.ActionEvent;

public class MenuBean {

   private MenuState menuState;

   public MenuState getMenuState() {
	return menuState;
   }
   public void setMenuState(MenuState menuState) {
	this.menuState = menuState;
   }
   public MenuBean() {}

   public void select (ActionEvent event) {
	menuState.setSelectedMenuItem(event.getComponent().getId());
   }
}

In select listener, we are remembering which rich:panelMenuItem was clicked. When we come back to the page, the clicked item will be italicized via selectedChild=”#{menuState.selectedMenuItem}”.

MenuState bean (in session scope) keeps the menu state.

package test;

import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;

public class MenuState {

private Map  menu;

   private String selectedMenuItem;

   public String getSelectedMenuItem() {
	return selectedMenuItem;
   }
   public Map getMenu() {
	return menu;
   }
   public void setMenu(Map menu) {
	this.menu = menu;
   }
   public void setSelectedMenuItem(String selectedMenuItem) {
	this.selectedMenuItem = selectedMenuItem;
   }
   public MenuState() {
   }
   @PostConstruct
   public void init () {
	menu = new HashMap ();
	menu.put("group1", false);
	menu.put("group2", false);
   }
}

rich:panelMenuGroup value attribute is bound to the menu HashMap and is saved automatically.

JSF configuration file:

 
  menuBean
  test.MenuBean
  request
  
   menuState
   test.MenuState
   #{menuState}
  
 

 
  menuState
  test.MenuState
  session
 

select.xhtml is very simple:


   
  	Go 
   

21 thoughts on “Keeping rich:panelMenu state

  1. Hello,

    the code works fine for me, menu State is stored etc.
    But the selectedChild is not “italicized” ….

    (Where) Do I have to define the style for it?
    (The menuItems all have a styleClass)

    thanks.

  2. Just found out theat when I switch to mode=”client” the style is ok.
    Only with “server roundtrip” it refuses to work.

  3. Ah…forget it. Just found out that I was storing a wrong value for the id.
    Once I did it right, it worked ….astonishing, isn`t it

  4. Hello Max,

    It works perfectly.
    But, I have same question asked by Karl. How to make selectedChild – italicized? I tried changing the mode =child, it gets italicized, but it does not go to the selected page specified in action =”…/xhtml”

    Thanks

  5. @Deepali: Did you mean to say mode=”client”? If it’s client, menu expands/collapses only on client, it doesn’t go to the server and thus no navigation is invoked.

  6. I’m trying to adapt this to seam, but am getting a NullPointerException inside menuBean.setSelected because menuState is Null, presumably because setMenuState in that same class is never called.

    I’m noticing JSF Configuration file, you have:

    menuState
    test.MenuState
    #{menuState}

    I’m guessing this may be the reason that setMenuState never gets called. How do I do the equivalent thing in seam?

    Also, I’m confused why each of the menu items inside start.xhtml reference select.xhtml but select.xhtml references start.xhtml. I have each of my menu items referencing a different .xhtml file; could that also be part of the problem?

  7. @Ken: In Seam, you would do the injection like this:

    @In
    private MenuState menuState;

    I did this post long time ago. I think every menu points to the same page because it’s just an example. You can set each menu to any other page. Hope this helps.

  8. Hi, I am using this solution… but I can observe a problem:

    I have 2 xhtml files: a.xhtml, b.xhtml and the following menu item:

    The application starts in page a.xhtml. When the user presses the item “Item 1” , then the application is redirected to page b.xhtml (correct), but in the web browser I can see still the URL a.xhtml

    I think there is some problem with having an actionListener and an action for the same menu item..

    Could you give me any idea of what could be the problem, and if it is possible, some suggestion to this.

    Thanks!!

  9. @david jimenez: If you still want to include the code, please use pastie.org. By default, when you navigate in JSF, it does a server-side forward. In other words, you submit the page1.jsf, then on the server you forward to page2.jsf – the URL in the browser says page1.jsf. That’s just how JSF works when doing a forward. You can do a redirect, the URL will then match the page but you will do two requests. To do a redirect, set:

    
    

    in navigation rules. Hope this helps.

      1. Thank you for the answer, I’ll try it and then repor with feedback 🙂

        (also, obviously i meant richfaces, not rochfaces 😛 )

      1. I think something didn’t go smoothly when I migrated my blog to maxkatz.org. I don’t have the original files.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s