Reputation: 3
I´m trying to implement a multi-field (e.g. two inputText-fields) validation under JSF2.0. Unfortunally the attributes are not set right in the validator.
The behaviour is as follows:
When I submit the first entry of both input-fields the attributes in the validator are null. In the 2nd submit the values are filled correctly. In the 3rd submit I can see the values of the 2nd request, but not of the 3rd.. This is quite a strange behaviour.
In the following you can see my testcode.
TestValidator.class
@FacesValidator(value="testValidator")
public class TestValidator implements Validator {
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
UIInput c1 = (UIInput) context.getViewRoot().findComponent("input1");
if (c1 != null) {
Object s1 = (Object) c1.getSubmittedValue();
}
UIInput c2 = (UIInput) context.getViewRoot().findComponent("input2");
if (c2 != null) {
Object s2 = (Object) c2.getSubmittedValue();
}
String c5 = (String) component.getAttributes().get("input1");
String c6 = (String) component.getAttributes().get("input2");
}
}
I try to grab the attributes in two differnt ways. Unfortunally without success. The parameter value is always set right.
test.xhtml
This is my first try with f:attribute attached to the 2nd inputText-field
<h:form id="test">
<h:inputText value="#{testModelBean.input1}" maxlength="10" size="4">
</h:inputText>
<h:inputText value="#{testModelBean.input2}" maxlength="10" size="4">
<f:validator validatorId="testValidator" />
<f:attribute name="input1" value="#{testModelBean.input1}" />
<f:attribute name="input2" value="#{testModelBean.input2}" />
</h:inputText>
<h:commandButton action="#{testControllerBean.doAction}" />
</h:form>
This my 2nd with h:inputHidden:
<h:form id="test">
<h:inputHidden value="true">
<f:validator validatorId="testValidator" />
<f:attribute name="input1" value="#{testModelBean.input1}" />
<f:attribute name="input2" value="#{testModelBean.input2}" />
</h:inputHidden>
<h:inputText value="#{testModelBean.input1}" maxlength="10" size="4">
</h:inputText>
<h:inputText value="#{testModelBean.input2}" maxlength="10" size="4">
</h:inputText>
<h:commandButton action="#{testControllerBean.doAction}" />
</h:form>
In both cases the behaviour is the same as mentioned above.
My TestModelBean is quite simple
TestModelBean.class
@ManagedBean(name="testModelBean")
@SessionScoped
public class TestModelBean implements Serializable {
private String input1;
private String input2;
public String getInput1() {
return input1;
}
public void setInput1(String input1) {
this.input1 = input1;
}
public String getInput2() {
return input2;
}
public void setInput2(String input2) {
this.input2 = input2;
}
}
My TestControllerBean is simple too:
TestControllerBean.class
@ManagedBean(name="testControllerBean")
@SessionScoped
public class TestControllerBean
implements Serializable {
public String doAction() {
return "success";
}
}
Now my question is, if anyone has an idea, why the attributes are not filled right in every submit/request. Or is there a different way to access the attributes? Is there a certain order I should take care of (concerning DOM or JSF Lifecycle)?
Upvotes: 0
Views: 2006
Reputation: 11742
You seem to misunderstand the lifecycle of JSF. Model values are updated at a later phase (Update model values phase) than JSF validation happens (Process validations phase). Therefore, when you expect to get a new model value it's not been yet set. As a consequence, you get the old value from your @SessionScoped
bean.
See Debug JSF lifecycle and The JSF application lifecycle for an overview of JSF lifecycle.
How can you overcome this situation? You can bind a full component as an attribute of the desired component and use UIInput
methods UIInput#getValue()
and UIInput#getSubmittedValue()
respectively to get either the converted/validated value of component (for bound components that are located before the component in question in JSF component tree) or the raw submitted value (for bound components that are located after the component in question in JSF component tree).
All in all, you'd need to change your code to the following:
The view:
<h:inputText value="#{testModelBean.input1}" binding="#{input}" />
<h:inputText value="#{testModelBean.input2}">
<f:validator validatorId="testValidator" />
<f:attribute name="input1" value="#{input}" />
</h:inputText>
The validator method snippet:
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
UIInput input = (UIInput)component.getAttributes().get("input");
String inputString = (String)input.getValue();
//etc.
}
See JSF getValue() v.s. getSubmittedValue(), JSF doesn't support cross-field validation, is there a workaround? and JSF validate on submit form for an overview.
Upvotes: 2