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?
#{date1input}
doesn't referid="date1input"
, instead it's supposed to referbinding="#{date1input}"
. Check those examples more carefully. – BalusCbinding
: carefully read this how to properly use it. It's indeed evil when misunderstood and misused. As to "best" approach, have you looked at the OmniFaces way in the linked duplicate? No binding, no f:attribute, no other mess. Just a<o:validateOrder components="startDateId endDateId" />
tag and that's it. – BalusC