I do not understand the behaviour of JSF2 during valdation. Hope someone can help me.
I have a form where the fields are validated after (ajax) submit - ok
If the validation failed a error message is shown - ok
For my example when I enter a valid birthday and the field name is empty an errormessage for name is shown after submit.
Now when I enter a valid name and delete the input from the birthday field an errormessage is show for birthday (that's ok) but now the old 'valid' birthday stands also in the input field!?!
How can I avoid this behaviour? When I submit an empty field I want to see an errormessage and an empty field...
Here's my sample code:
I use a ManagedBean (TestBean) that contains an EntityBean (Contact). The Contact contains validations per annoations.
public class Contact implements Serializable {
@NotNull
@Temporal(TemporalType.DATE)
private Date birthday;
@NotNull
@Size(min=3, max=15)
private String name;
//...
}
My ManagedBean:
@ManagedBean
@ViewScoped
public class TestBean implements Serializable {
private Contact contact;
@PostConstruct
void init() {
System.out.println("init...");
contact = new Contact();
}
public void newContact(ActionEvent ae) {
System.out.println("newContact...");
contact = new Contact();
}
public void save() {
System.out.println("save...");
//TODO do something with contact...
}
public Contact getContact() { return contact; }
public void setContact(Contact contact) {this.contact = contact;}
}
An here my JSF page:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" >
<h:body>
<h:form>
<h:panelGrid columns="3">
<h:outputText value="Birthday: " />
<h:inputText id="birthday" value="#{testBean.contact.birthday}">
<f:convertDateTime/>
</h:inputText>
<h:message for="birthday" />
<h:outputText value="Name: " />
<h:inputText id="name" value="#{testBean.contact.name}"/>
<h:message for="name" />
</h:panelGrid>
<h:commandButton value="submit" action="#{testBean.save}">
<f:ajax execute="@form" render="@form"/>
</h:commandButton>
<h:commandButton value="newContact" actionListener="#{testBean.newContact}"
immediate="true">
<f:ajax render="@form"/>
</h:commandButton>
</h:form>
</h:body>
</html>
at last a snippet from web.xml
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
<param-value>true</param-value>
</context-param>
Thanks for some tips
Your particular problem is caused by
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
and a bug (at least, an oversight) in HtmlBasicRenderer#getCurrentValue()
of Mojarra:
if (component instanceof UIInput) {
Object submittedValue = ((UIInput) component).getSubmittedValue();
if (submittedValue != null) {
// value may not be a String...
return submittedValue.toString();
}
}
String currentValue = null;
Object currentObj = getValue(component);
if (currentObj != null) {
currentValue = getFormattedValue(context, component, currentObj);
}
return currentValue;
Normally, the submitted value is set to null
when the UIInput
component is successfully converted and validated. When JSF is about to redisplay the value, it first checks if the submitted value is not null
before proceeding to redisplay the model value. However, with this context parameter, it is null
instead of an empty string when it is invalid and thus it will always redisplay the original model value when you remove the initial value of a required field.
To test it, set that context param value to false
or remove it altogether. You'll see that it works as intended. However, it will bring back the disadvantage that your model values will be cluttered with empty strings on empty but non-required fields and you'll lose the advantage of using @NotNull
annotation of JSR 303 bean validation.
To fix this, you've to alter the first part of HtmlBasicRenderer#getCurrentValue()
as follows:
if (component instanceof UIInput && !((UIInput) component).isValid()) {
Object submittedValue = ((UIInput) component).getSubmittedValue();
if (submittedValue != null) {
// value may not be a String...
return submittedValue.toString();
} else {
return null;
}
}
I've already reported it to Mojarra guys as issue 2266.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With