views:

954

answers:

2

I'm creating a MenuItem dynamically and I want to add a custom listener when the MenuItem is clicked.

I've tried adding addActionListener and setActionListener but neither of these get called when the link is clicked.

It appears that there is a List called "listeners" attached to MenuItem (I can see this when debugging a MenuItem setup with the listener statically). Any idea how to add the listener correctly?

+1  A: 

They needs to be created and added as follows (copied from one of my previous answers):

FacesContext context = FacesContext.getCurrentInstance();
MethodExpression actionListener = context.getApplication().getExpressionFactory()
    .createMethodExpression(context.getELContext(), "#{bean.actionListener}", null, new Class[] {ActionEvent.class});
uiCommandComponent.addActionListener(new MethodExpressionActionListener(actionListener));

...where #{bean.actionListener} actually exists and is declared like follows in the backing bean class associated with the managed bean name bean:

public void actionListener(ActionEvent event) {
    // ...
}

More importantingly, you need to give any dynamically created UICommand (and UIInput) component in question a fixed ID as well, else it will get an autogenerated ID which may cause that JSF cannot locate/correlate it during the apply request values phase.

Thus, do so as well:

uiCommandComponent.setId("someFixedId");
BalusC
Then you're apprarently still using the old JSF 1.0/1.1 (which has been replaced by 1.2 over 4(!!) years ago). Click the aforementioned link to see the JSF 1.1 way to create an `ActionListener`. You **still** need to set a fixed ID yourself!
BalusC
It turns out there was a reference in Maven to another project which was using MyFaces and even though I had JSF 1.2 it was not compiling :-)...Thanks again for your reply.
DD
One unique ID per component. You can if necessary add some counter to it, e.g. `child.setId("someFixedId" + parent.getChildCount()); parent.getChildren().add(child);`
BalusC
wow...that kind of sucks that I need to come up with a unique naming strategy just to add a listener!
DD
It isn't that hard if you do it the smart way, also see the code example in the comment. Alternatively you can also grab `UIViewRoot#createUniqueId()`: http://java.sun.com/javaee/6/docs/api/javax/faces/component/UIViewRoot.html#createUniqueId%28%29
BalusC
thanks very much for your help....I dont think my component extends UIViewRoot...can I still use this?
DD
It's just available by `FacesContext#getViewRoot()` :)
BalusC
Not exactly sure what is going on but for some reason IceFaces keeps recreating my menus...the createUniqueID keeps changing...and the event listeners arent getting called. Works fine with the counter methodology but its harder to test.
DD
A: 

The main issue as pointed out by BalusC is that you need to set the ID. Then you can add event listeners as follows: private MenuItem createItem(String name){ MenuItem item=new MenuItem(); item.addActionListener(new ActionListener() {

        public void processAction(ActionEvent event)
                throws AbortProcessingException {
            // handle event

        }
    });
    item.setValue(name);
    return item;
}
DD