I've a form in JSF 2 where I'm using a double field to specify a range of dates. The aim of that is not to let the user to pick a first date which is before the second one. So I want to perform a validation before the form is sent, using p:calendar
components. What I do is to tie a validator to the second calendar input in order to access the first component internally and compare dates.
Here it is my xhtml 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"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head />
<h:body>
<h:form id="date_form">
<p:calendar id="date1input" value="#{dateTestBean.date1}" />
<p:calendar value="#{dateTestBean.date2}" validator="dateValidator">
<f:attribute name="date1" value="#{date1input}" />
</p:calendar>
<p:commandButton value="Submit" action="#{dateTestBean.submit}"
ajax="false" />
</h:form>
</h:body>
</html>
My managed bean:
@ManagedBean
@ViewScoped
public class DateTestBean {
private Date date1;
private Date date2;
public Date getDate1() {
return date1;
}
public void setDate1(Date date1) {
this.date1 = date1;
}
public Date getDate2() {
return date2;
}
public void setDate2(Date date2) {
this.date2 = date2;
}
public void submit() {
System.out.println("Submited " + date1 + " " + date2);
}
}
My validator class:
@FacesValidator(value = "dateValidator")
public class DateValidator implements Validator {
@Override
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
System.out.println(((UIInput) context.getViewRoot().findComponent(
"date_form:date1input")).getValue());
UIInput date = (UIInput) component.getAttributes().get("date1");
System.out.println(date);
//Will perform date comparison
}
}
The output I get here sending 2013-10-10
as first date and 2013-10-12
as second one is:
Thu Oct 10 00:00:00 CEST 2013
null
Submited Thu Oct 10 00:00:00 CEST 2013 Sat Oct 12 00:00:00 CEST 2013
Which suggests f:attribute
tag is not working for p:calendar
component as it does for other input components. However, I can access the first calendar via view root, but enforces me to know the entire path of the client id of the component I want to validate. Both values are set in the managed bean later with no issues.
A workaround would be to use an ajax call when first date changes in order to place it in the model and send it as date itself in the f:attribute
instead of sending the UIInput (I'm already doing it that way).
Isn't there a better way? Perhaps I have to join them in a single component like in this case?