Error validating two inputText fields together
I have a form with two input fields that have to be validated together. I used this BalusC tutorial as starting point.
The requirement is a logical XOR: one of the fields must be filled but not both together.
This works fine for all cases except this one:
开发者_运维百科1) Fill the first field and let the second blank
2) Move to the next page (values get saved)
3) Go back to the first page, delete first field and fill second field.
Then I get the error message from my validator ("Do not fill both fields") although I deleted the first.
Here is the code:
<h:inputText id="bbvol" size="10" value="#{a6.behandlungsvolumen.wert}"
required="#{empty param['Laborwerte:pvol']}">
<f:convertNumber locale="de"/>
</h:inputText>
<h:inputText id="pvol" size="10" value="#{a6.plasmavolumen.wert}"
required="#{empty param['Laborwerte:bbvol']}">
<f:convertNumber locale="de"/>
<f:validator validatorId="volumeValidator" for="pvol"/>
<f:attribute name="bbv_value" value="Laborwerte:bbvol" />
</h:inputText>
VolumeValidator:
public class VolumeValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
// Obtain the client ID of the first volume field from f:attribute.
String bbvolID = (String) component.getAttributes().get("bbv_value");
// Find the actual JSF component for the client ID.
UIInput bbvolInput = (UIInput) context.getViewRoot().findComponent(bbvolID);
// Get its value, the entered value of the first field.
Number bbvol = (Number) bbvolInput.getValue();
// Get the value of the second field
Number pvol = (Number) value;
// Check if only one of the fields is set
if (bbvol != null && pvol != null) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Do not fill both fields!", null));
}
}
}
Debugging this case reveals that the line
Number bbvol = (Number) bbvolInput.getValue();
still holds the old value and not the new.
I tried to use getSubmittedValue()
instead of getValue()
and this works. But javadoc for this method says:
This method should only be used by the decode() and validate() method of this component, or its corresponding Renderer.
I am not sure if I can use this method without running in problems later.
So my questions are:
What is the reason for this issue?
Is using getSubmittedValue()
instead of getValue()
a real solution?
This does not solve the problem. If you test getSubmittedValue()
, then the validation will (incorrectly) pass when you fill both fields. In JSF, input components are validated in the order as they appear in the component tree. When a component is successfully been converted/validated, then the submitted value is set to null
and the value is set with the converted/validated submitted value.
However, your particular case strikes me. I can replicate this problem with Mojarra 2.0.4 on Tomcat 7.0.11. The getValue()
returns the model value instead of the component value. I'm not sure if that's a bug or new in JSF2 or something, I am however confident that it has worked that way in JSF 1.x. I believe this is related to changes with regard to the new JSF2 state management. I have to verify the one and other first (and probably also rewrite the multiple field validation blog article).
As another solution you could add a <h:inputHidden>
before the two components as follows so that you can utilize getSubmittedValue()
the right way:
<h:form id="form">
<h:inputHidden value="true">
<f:validator validatorId="xorValidator" />
<f:attribute name="input1" value="form:input1" />
<f:attribute name="input2" value="form:input2" />
</h:inputHidden>
<h:inputText id="input1" value="#{bean.input1}" required="#{empty param['form:input2']}" />
<h:inputText id="input2" value="#{bean.input2}" required="#{empty param['form:input1']}" />
<h:commandButton value="submit" action="#{bean.submit}" />
<h:messages />
</h:form>
with
@FacesValidator(value="xorValidator")
public class XorValidator implements Validator {
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
UIInput input1 = (UIInput) context.getViewRoot().findComponent((String) component.getAttributes().get("input1"));
UIInput input2 = (UIInput) context.getViewRoot().findComponent((String) component.getAttributes().get("input2"));
Object value1 = input1.getSubmittedValue();
Object value2 = input2.getSubmittedValue();
// ...
}
}
Apart from the {feature|bug} with the getValue() / getSubmittedValue() - methods in 2.x you could try the RequiredIf-Annotation for XOR validation:
@RequiredIf(validationErrorMsgKey = "requiredField", valueOf = { "pvol" } , is = RequiredIfType.empty )
private String bbvol;
@RequiredIf(validationErrorMsgKey = "requiredField", valueOf = { "bbvol" } , is = RequiredIfType.empty )
private String pvol;
That works for me like a charm in a similiar validation constellation.
精彩评论