17 Nov 2013

Validating dates with af:validateDateTimeRange validator

Sometimes we need to validate that the date entered in an af:inputDate component is within some range. ADF Faces provides a very convenient approach for that - af:validateDateTimeRange. It is very easy to use and it could look like this in a jspx code:
<af:inputDate value="#{dateValue}">
   <af:validateDateTimeRange minimum="#{minimumValue}"
        messageDetailNotInRange="The date value {1} is not in the range {2} - {3}"
But there is some pitfall to be aware.

Let's say we've got some ViewObject with three oracle.jbo.domain.Date attributes - ValueDate, MaturityDate and PaymentDate:

We put correspondent inputDate components on a page and set up autoSubmit attribute for ValueDate and MaturityDate:

We need to keep the value of PaymentDate within the range between ValueDate and MaturityDate. So, w're going to add a validator to the PaymentDate:

<af:inputDate value="#{bindings.PaymentDate.inputValue}"
  <f:validator binding="#{bindings.PaymentDate.validator}"/>
  <af:convertDateTime pattern="#{bindings.PaymentDate.format}"/>
  <af:validateDateTimeRange minimum="#{bindings.Valuedate.inputValue.value}"

And let's test it now:

The error message is absolutely correct since PaymentDate is less than ValueDate.

The value of PaymentDate is equal to ValueDate and it is within the range ValueDate-MaturityDate. So there is no any validation exception.

Ooops!  The value of PaymentDate is equal to MaturityDate and it is within the range ValueDate-MaturityDate. But the validation exception is fired.
We can figure out the reason of this strange behavior in the specification of the maximum attribute of the af:validateDateTimeRange:

"... When binding to Date objects, it is advised to create the Date object with maximum value for any date-time components that aren't displayed (usually hours, minutes, seconds, milliseconds) to allow the largest range of values to be accepted."

So, in order to get it working correctly, it is advised to specify in the maximum attribute of the validateDateTimeRange something like this: "5/24/2012 23:59:59.999".

Let's give it what it wants. In our ViewObject we created a transient oracle.jbo.domain.Date attribute LimitMaturityDate with the following value expression:

 The expression actually adds a day (24 hours) to the Maturitydate and subtracts a milisecond, so we're going to get "Maturitydate 23:59:59.999". The new java.sql.Timestamp object is going to be converted into the oracle.jbo.domain.Date by the framework. And let's use this transient attribute as a maximum for the af:validateDateTimeRange:
  <af:validateDateTimeRange minimum="#{bindings.Valuedate.inputValue.value}"

And if we test it again:

It will work fine.

That's it!

No comments:

Post a Comment

Post Comment