Thursday, July 19, 2012

Compare two dates in two <rich:calendar> components

In this lesson Im going to show you how to compare the dates of two &lt;rich:calendar> components in a JSF page.

For an example think that you are creating a JSF page to enter employee details.
In that page you have two calendar components. One is to enter the join date and the other one is to enter the retired date of the employee.
So obviously join date should be earlier than the retired date. How do you validate whether join date is earlier than retired date and show a rich:message if validation failed?

1) Method 1 (For JSF users)
If you are not using JBoss SEAM, this method is for you. (Its obvious that SEAM users also can use this method.)

First, you have to create a validator class as below.


package inova;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;


public class DateComparator implements Validator {
public void validate(FacesContext context, UIComponent component, Object date1) throws ValidatorException {
Date joinedDate = (Date) date1;
UIInput retiredDateComponent = 
           (UIInput) component.getAttributes().get("retiredDateComponent");

String dateString = (String) retiredDateComponent.getSubmittedValue();
System.out.println("dateString>" + dateString);
        String pattern = "yyyy/MM/dd hh:mm";
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        Date retiredDate;
        try {
        retiredDate = dateFormat.parse(dateString);        
        } catch (ParseException e) {
            e.printStackTrace();
            return;
        }
        System.out.println("retiredDate> " + retiredDate);
if (joinedDate == null || retiredDate == null) {
            return;
}
        if (joinedDate.compareTo(retiredDate) > 0) {
        retiredDateComponent.setValid(false);
            throw new ValidatorException(new FacesMessage("Retired date should be 
                greator than joined Date"));
        }
    }
}
Now register your validator class in your 'faces-config.xml' file. To do it add the following lines directly within the <faces-config> tags.


<validator-id>dateComparator</validator-id>
  <validator-class>inova.DateComparator</validator-class>
</validator>
Note that 'dateComparator' is the name by using which you are going to access the validator in your page. You can give any name for this.

If you are using a date pattern in your second calendar(end date) component, you have to use the same date pattern in your validator class.
Your page will be as below.


<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:rich="http://richfaces.org/rich"
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:c="http://java.sun.com/jstl/core"
      xmlns:f="http://java.sun.com/jsf/core"> 


<head></head> 
<body>
  <h:form>
    Start date : 
    <rich:calendar id="cal_1">
      <f:validator validatorId="dateComparator"/>
      <f:attribute name="endDateComponent" value="#{endDate}"/>
    </rich:calendar>
    <br/>
    End date : <rich:calendar binding="#{endDate}" datePattern="yyyy/MM/dd hh:mm"/> 
    <br/>
    <rich:message for="cal_1" style="color:red;"/>
    <br/>
    <a4j:commandButton value="Save"/>
  </h:form>
</body> 
</html>

That is all. I think its clear for you what we have done.
♫ In our xhtml page we bind the 'end date calendar' component to the variable named as 'endDate' by using the 'binding' attribute of it.
♫ Then in our 'start date calendar' component, we use it as an attribute.
♫ In our validator class, we get that attribute by using the 'component.getAttributes().get(....)' method. Then we get the end date.
♫ If two dates are valid according to our criteria, we have nothing to do and if dates are invalid we throws a 'ValidatorException' with our own message.

2) Method 2(For seam users only)
This way is easier than the above method.
 The validator class is almost the same as above except three annotations are introduced before the class name as below.


@Name("dateComparator")
@org.jboss.seam.annotations.faces.Validator
@BypassInterceptors
public class DateComparator implements Validator {
..........
}
✱  Nothing to be put in faces-config.xml. It means you don't need to register your validator class in  faces-config.xml as in method1.

Enjoy......

No comments:

Post a Comment