Search code examples
primefacesmenumenuitem

Dynamic p:menu works in PrimeFaces 3.5, not in >4.0


I'm updating a project from Primefaces 3.5 to 4.0 and I've got problem with menu. I can't understand how to create dynamically a simple menu like this:

<p:menu>
    <p:submenu>
        <p:menuitem value="jump" action="myTransition" />
    </p:submenu>
</p:menu>

I try to set the command of the item with the name of the transition, defined in my Spring web flow configuration, with no result.

DefaultMenuItem itemNone = new DefaultMenuItem();
item.setCommand("myTransition");

The plain menu work fine, but if I try the dynamic one the page just refresh, no errors or other evidence.

So, basically I need to port this code, from pf 3.5 to pf >4.0

for(String elem : list)
{
    MenuItem item = new MenuItem();
    item.setValue(elem.toUpperCase());
    item.setActionExpression(CommonUtils.createMethodExpressionInUIContext(FacesContext.getCurrentInstance(),  elem.replaceAll("\\s","").replace(".", ""),
                String.class, new Class[]{String.class}));
    submenu.getChildren().add(item);
}

with this function

public static MethodExpression createMethodExpressionInUIContext(final FacesContext facesContext, final String expression, Class<?> class1, Class[] classes) {

    FaceletContext faceletElContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
    MethodExpression methodExpression = FacesContext.getCurrentInstance().getApplication().getExpressionFactory()
            .createMethodExpression(faceletElContext, expression, class1, classes);

    return methodExpression;
}

My try with

DefaultMenuItem item = new DefaultMenuItem();    
item.setCommand(elem);

or

item.setCommand(CommonUtils.createMethodExpressionInUIContext(FacesContext.getCurrentInstance(),  elem.replaceAll("\\s","").replace(".", ""),String.class, new Class[]{String.class}).getExpressionString());

didn't work


Solution

  • Just to myself, from the past, to achieve my goal I followed these steps:

    • register my own Menu and MenuRenderer, that extends Primefaces version
    • define a new MenuItem with an additional field, for action command (named commandAction)
    • Override decode method as:

    MenuRenderer

    @Override
    public void decode(FacesContext context, UIComponent component) {
        AbstractMenu menu = (AbstractMenu) component;
        String clientId = menu.getClientId(context);
        Map<String, String> params = context.getExternalContext().getRequestParameterMap();
    
        if (params.containsKey(clientId)) {
            String menuid = params.get(clientId + "_menuid");
            DefaultMenuItem menuitem = (DefaultMenuItem) findMenuitem(menu.getElements(), menuid);
            MenuActionEvent event = new MenuActionEvent(menuitem, menuitem);
    
            // Action Listener
            if (StringUtils.isNoneBlank(menuitem.getCommand())) {
                menuitem.setActionExpression(CommonUtils.createMethodExpressionInUIContext(
                        FacesContext.getCurrentInstance(), menuitem.getCommand().replaceAll("\\s", "").replace(".", ""),
                        String.class, new Class[] { String.class }));
    
                if (menuitem.isImmediate()) {
                    event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
                } else {
                    event.setPhaseId(PhaseId.INVOKE_APPLICATION);
                }
                menu.queueEvent(event);
            }
    
            // Action
            if (StringUtils.isNoneBlank(menuitem.getCommandAction())) {
                menuitem.setActionExpression(CommonUtils.createMethodExpressionInUIContext(
                        FacesContext.getCurrentInstance(), menuitem.getCommandAction().replaceAll("\\s", "").replace(".", ""),
                        String.class, new Class[] { String.class }));
    
                if (menuitem.isImmediate()) {
                    event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
                } else {
                    event.setPhaseId(PhaseId.INVOKE_APPLICATION);
                }
                menu.queueEvent(event);
            }
        }
    }