Tuesday, 27 August 2013

jsf immediate attribute ajax vs input

jsf immediate attribute ajax vs input

I observed following behaviour in JSF:
A UIInput component triggered via AjaxBehaviour with 'immediate=true' does
not have the validator executed in the APPLY_REQUEST, but always in the
Phase determined by the UIInput itself. It means the AjaxBehaviour
'immediate' attribute has no effect on when the validator of the component
is processed. Which is IMO not what the describtion of AjaxBehaviour says:
The immediate attribute indicates whether user inputs are to be processed
early in the application lifecycle or later. If the attribute is set to
true, events generated from this component are broadcast during the Apply
Request Values phase. Otherwise, the events will be broadcast during the
Invoke Applications phase.
To be read at: Oracle Tutorial
Even thought in AjaxBehaviour.isImmediate(component,behaviour) JSF takes
care of having the AjaxBehaviour more important than the component
private boolean isImmediate(UIComponent component, AjaxBehavior
ajaxBehavior) {
boolean immediate = false;
if(ajaxBehavior.isImmediateSet()) {
immediate = ajaxBehavior.isImmediate();
} else if(component instanceof EditableValueHolder) {
immediate = ((EditableValueHolder)component).isImmediate();
} else if(component instanceof ActionSource) {
immediate = ((ActionSource)component).isImmediate();
}
return immediate;
}
Whereas in the UIInput.processDecodes(context) does not trigger the
validation in that phase because the component is not 'immediate' ..
public void processDecodes(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// Skip processing if our rendered flag is false
if (!isRendered()) {
return;
}
super.processDecodes(context);
if (isImmediate()) {
executeValidate(context);
}
}
Anyways; to reproduce my case:
A) The JSF code:
<h:selectBooleanCheckbox id="mandatory"
value="#{currentQuestion.mandatory}" label="#{texts.mandatory_Question}"
disabled="#{!bean.metadata.editable}" validator="mandatoryValidator"
onchange="makeDirty()" immediate="false">
<f:ajax event="click" execute="@this" render="@this :mandatory-msg"
immediate="true"/>
</h:selectBooleanCheckbox>
<h:outputLabel for="mandatory" value="#{texts.mandatory_Question}"
styleClass="standard-label chkBox-label" />
<p:message for=":mandatory" id="mandatory-msg" showDetail="true"
showSummary="true" />
B)The custom validator:
@FacesValidator("mandatoryValidator")
public class MandatoryValidator implements Validator {
/** logger. */
private static final Logger LOG =
Logger.getLogger(MandatoryValidator.class.getName());
/** {@inheritDoc} */
@Override
public final void validate(final FacesContext context, final UIComponent
component, final Object value) {
if (FacesContext.getCurrentInstance().getCurrentPhaseId() ==
PhaseId.APPLY_REQUEST_VALUES) {
LOG.debug("apply phase");
}
if (FacesContext.getCurrentInstance().getCurrentPhaseId() ==
PhaseId.PROCESS_VALIDATIONS) {
LOG.debug("validation phase");
}
}
In that example the validator will not be executed in the APPLY_REQUEST
until the SelectBoolCheckBox is also 'immediate=true'. Even worse, the
immediate of the component, even defaulted, always wins. Which makes the
AjaxBehaviour immediate attribute totally worseless.
Can anyone explain or reproduce or grunt with me?

No comments:

Post a Comment