RichFaces Dynamic Menu, Finding Ajax Form, Custom Method Expression and Parameterized Action

Here is a common scenario you will come across while using JSF with RichFaces

Creating Dynamic RichMenu
Register the menu component in your view (Facelets or JSP)

<rich:dropdownmenu binding="#{bean.menuComponent}" value="File">

In the backing bean, use the component binding to create Menu Items programmatically
private HtmlDropDownMenu menuComponent;

public HtmlDropDownMenu getMenuComponent() {
FacesContext ctx = FacesContext.getCurrentInstance();
Application app = ctx.getApplication();
if(null == menuComponent)
menuComponent = (HtmlDropDownMenu)app.createComponent(HtmlDropDownMenu.COMPONENT_TYPE);
for(String key: map.keySet()) {
HtmlMenuItem item = (HtmlMenuItem)app.createComponent(HtmlMenuItem.COMPONENT_TYPE);
item.setValue(key);
item.setId(key);
Class[] params = {};
MethodExpression actionExpression = app.getExpressionFactory()
.createMethodExpression(ctx.getELContext(),
"#{bean.menuAction}",
String.class, params);
item.setActionExpression(actionExpression);
String onSelect = "open(this,'"+map.get(key).toString()+"')";
item.setOnselect(onSelect);
menuComponent.getChildren().add(item);
}
return menuComponent;
}

Notice how you can programmatically create a Mexpression in JSF 1.2 via UEL
Also, see how JavaScript event is wired to the dynamically created RichMenuItem

Finding the Form
RichFaces has a convenient JavaScript function A4J.findForm which you can use to locate the form corresponding to the Menu Item

function open(el, paramValue) {
var frm = A4J.findForm(el);
if(frm == null) {
alert("open: no form found.");
return;
}
//add hidden parameter
var hidden = document.createElement('input');
hidden.setAttribute('name', 'PARAM_NAME');
hidden.setAttribute('type', 'hidden');
hidden.setAttribute('value', paramValue);
frm.appendChild(hidden);

frm.submit();
}

Managed Bean Action method
From the action method, find the value of interest and take appropriate action

public void menuAction (){
FacesContext facesContext = FacesContext.getCurrentInstance();
Application app = facesContext.getApplication();
Map reqMap = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String param = reqMap.get(name).toString();
}




Feel free to use this code in your applications.
If you found this useful, please leave your comments / feedbacks that would prove helpful for the developer community.

Reactions: 

13 comments:

ismaelarias said...

No way
----------------------
Error: A4J is not defined
Archivo de origen: http://localhost:8080/menu/ Línea: 1
----------------------
in javascript console
Any sugestion?

pangare said...

no way
-------------------------
Error: A4J is not defined
Archivo de origen: http://localhost:8080/menu/ Línea: 1
-------------------------
in javascript console
any sugestion...

alvaro said...

hello
thanks for your tip, run ok

alvaro said...

i forget, i change the name of the java script, with open don't run.

Hadi said...

but what if I wanna use this code to navigate to another page
the menuAction() method is not invoking at all

Hadi said...

what if i want to use this code to navigate to another page

the method menuAction() is not called

Radhesh said...

Hadi,

Your menuAction method should return a "String" that identifies the next view defined in your faces-config file.

Hadi said...

ok but the menuAction() is not called at all
i have changed the return type and nothing happened

Anonymous said...

I can't get the javscript function 'open' to fire.

The browser keeps reporting an error 'Error Permission Denied'

Any ideas?

Prashanth said...

I'm getting the following error when I tried it

Caused by: javax.el.PropertyNotFoundException: /layout/leftNav.xhtml @60,75 binding="#{dynMenu.menuComponent}": Property 'menuComponent' not found on type com.test.DynamicMenu_$$_javassist_1

I have reused the code given here but it gave me the error as shown above. Could you please let me know what mistake I have done here.

Radhesh said...

Prashanth,

Please make sure that you have a method with the following signature on com.test.DynamicMenu (which is your backing bean referenced by "dynMenu")

public HtmlDropDownMenu getMenuComponent() {
...

Naveen Kumar said...

This post was very useful to know how to get params in jsf

Anonymous said...

hi! Thanks for your great post :)
Can you provide a sample in how we can have a sub menu?
Example:
Menu 1
Menu 2
Sub-Menu 2-1
Sub-Menu 2-2
Menu 3
Can we achieve that dynamically?
Thanks!