What's the difference between the following two pieces of code - with regards to listener placement?
<h:selectOneMenu ...>
<f:selectItems ... />
<f:ajax listener="#{bean.listener}" />
</h:selectOneMenu>
and
<h:selectOneMenu ... valueChangeListener="#{bean.listener}">
<f:selectItems ... />
</h:selectOneMenu>
The
valueChangeListenerwill only be invoked when the form is submitted and the submitted value is different from the initial value. It's thus not invoked when only the HTML DOMchangeevent is fired. If you would like to submit the form during the HTML DOMchangeevent, then you'd need to add another<f:ajax/>without a listener(!) to the input component. It will cause a form submit which processes only the current component (as inexecute="@this").When using
<f:ajax listener>instead ofvalueChangeListener, it would by default executed during the HTML DOMchangeevent already. InsideUICommandcomponents and input components representing a checkbox or radiobutton, it would be by default executed during the HTML DOMclickevent only.Another major difference is that the
valueChangeListenermethod is invoked during the end of thePROCESS_VALIDATIONSphase. At that moment, the submitted value is not been updated in the model yet. So you cannot get it by just accessing the bean property which is bound to the input component'svalue. You need to get it byValueChangeEvent#getNewValue(). The old value is by the way also available byValueChangeEvent#getOldValue().The
<f:ajax listener>method is invoked duringINVOKE_APPLICATIONphase. At that moment, the submitted value is already been updated in the model. You can just get it by directly accessing the bean property which is bound to the input component'svalue.Also, if you would need to update another property based on the submitted value, then it would fail when you're using
valueChangeListeneras the updated property can be overridden by the submitted value during the subsequentUPDATE_MODEL_VALUESphase. That's exactly why you see in old JSF 1.x applications/tutorials/resources that avalueChangeListeneris in such construct been used in combination withimmediate="true"andFacesContext#renderResponse()to prevent that from happening. After all, using thevalueChangeListenerto execute business actions has actually always been a hack/workaround.Summarized: Use the
valueChangeListeneronly if you need to intercept on the actual value change itself. I.e. you're actually interested in both the old and the new value (e.g. to log them).Use the
<f:ajax listener>only if you need to execute a business action on the newly changed value. I.e. you're actually interested in only the new value (e.g. to populate a second dropdown).If you're actually also interested in the old value while executing a business action, then fall back to
valueChangeListener, but queue it to theINVOKE_APPLICATIONphase.