Valuechangelistener on <p:selectOneMenu> works but an Exception is being thrown. Why?

ClydeFrog picture ClydeFrog · Jul 27, 2012 · Viewed 10.4k times · Source

I'm using Primefaces 3.3.1 and have a <p:selectOneMenu> where I'm selecting a new value. When selecting a new value a valueChangeListener-method is being called where the value is being processed. Like this:

<h:form>
    <p:selectOneMenu id="signature-menu" value="#{objectBuffertBean.loggedInSignature}" effect="fold" style="width: 125px;">
        <p:ajax event="change" update="signature-menu" 
                listener="#{loginBean.changeSignature()}" />
        <f:selectItems value="#{signaturesBean.signatures}" />
    </p:selectOneMenu>
</h:form>

LoginBean.java:

public void changeSignature(ValueChangeEvent e) {
    if (e.getNewValue() != null) {
        try {
            WebDB db = new WebDB();

            SessionHandler.getInstance().
                    getCurrentObjectBuffert().setSignature(
                    db.getSignatureBySignatureFromWebDb(
                                           (String) e.getNewValue()
                    ));
        } catch (DatabaseException e1) {
            e1.printStackTrace();
        }
    }
}

But, the strange thing is that when I'm selecting a new value I get this exception:

javax.el.MethodNotFoundException: Method changeSignature not found

And it works! the method is being called somehow and the new value is being processed!! Is there anyone who have had the same strange complication?

Answer

BalusC picture BalusC · Jul 27, 2012

You're confusing valueChangeListener attribute of UIInput with listener attribute of <p:ajax>/<f:ajax>. The ValueChangeEvent argument is only supported on the method behind valueChangeListener attribute. The method behind the listener attribute of <p:ajax>/<f:ajax> must take AjaxBehaviorEvent argument (or just nothing).

So

 public void changeSignature(AjaxBehaviorEvent e) {
     if (loggedInSignature != null) {
         // ...
     }
 }

or

 public void changeSignature() {
     if (loggedInSignature != null) {
         // ...
     }
 }

Note that the submitted value is already set on the property behind the UIInput component's value attribute, so there's no need to get it by the event somehow. This is because this runs during invoke action phase instead of the validations phase like the valueChangeListener. Also, the valueChangeListener should technically only be used when you intend to have both the old and the new value in the method.


Unrelated to the concrete problem, the event="change" attribute of <p:ajax> is already the default. You can just omit it. Also those method parentheses from the listener attribute should preferably be omitted as it adds no value. Just use listener="#{loginBean.changeSignature}".