tags:

views:

35

answers:

2

Hi, can I validate two interdependent fields in with one validator?

     <h:form>
            <h:inputText value="#{logRegBean.person.name}" >
                <f:validator validatorId="loginCorrectValidator" />
            </h:inputText>
            <h:inputSecret value="#{logRegBean.person.password}" />
            <h:commandButton action="#{logRegBean.login}" />
        </h:form>

I want to search for the user in the DB and if there is the user, I'll test if the passwords(in db and inputted) match. But how can I access even the password field in one validator? I tried to evaluate the value int the other field via createValueExpression(), but it looks like I can't access the value in that time since I always get empty strings.

+1  A: 

Best what you can do is to grab the other UIInput component by UIViewRoot#findComponent() inside the validate() method and then determine the submitted value by either UIInput#getSubmittedValue() (when it occurs after the currently validated component in the component tree) or UIInput#getValue() (when it occues before the current component and thus is already validated).

E.g.

public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
    UIInput otherInput = (UIInput) context.getViewRoot().findComponent("clientId");
    String otherValue = (String) otherInput.getSubmittedValue();
    // ...
}

See also:

BalusC
+1  A: 

The validation mechanism in JSF was designed to validate a single component.
However, in practice, you often need to ensure that related components have reasonable values before letting the values propagate into the model.
For example, it is not a good idea to ask users to enter a date into a single textfield.
Instead, you would use three different textfields, for the day, month, and year.

If the user enters an illegal date, such as February 30, you would like to show a validation error and prevent the illegal data from entering the model.

The trick is to attach the validator to the last of the components. By the time its validator is called, the preceding components passed validation and had their local values set. The last component has passed conversion, and the converted value is passed as the Object parameter of the validation method.

Of course, you need to have access to the other components. You can easily achieve that access by using a backing bean that contains all components of the current form. Simply attach the validation method to the backing bean:

public class BackingBean {

    private int day;
    private int month;
    private int year;

    private UIInput dayInput;
    private UIInput monthInput;
    private UIInput yearInput;

    // PROPERTY: day
    public int getDay() { return day; }
    public void setDay(int newValue) { day = newValue; }

    // PROPERTY: month
    public int getMonth() { return month; }
    public void setMonth(int newValue) { month = newValue; }

    // PROPERTY: year
    public int getYear() { return year; }
    public void setYear(int newValue) { year = newValue; }

    // PROPERTY: dayInput
    public UIInput getDayInput() { return dayInput; }
    public void setDayInput(UIInput newValue) { dayInput = newValue; }

    // PROPERTY: monthInput
    public UIInput getMonthInput() { return monthInput; }
    public void setMonthInput(UIInput newValue) { monthInput = newValue; }

    // PROPERTY: yearInput
    public UIInput getYearInput() { return yearInput; }
    public void setYearInput(UIInput newValue) { yearInput = newValue; }

    public void validateDate(FacesContext context, UIComponent component, Object value) {

       int d = ((Integer) dayInput.getLocalValue()).intValue();
       int m = ((Integer) monthInput.getLocalValue()).intValue();
       int y = ((Integer) value).intValue();

       if (!isValidDate(d, m, y)) {
          throw new ValidatorException(new FacesMessage("Invalid Date"));
       }

    }

    private static boolean isValidDate(int d, int m, int y) {
        //DO YOUR VALIDATION HERE
    }

 }

Here is your JSP

 <html>

   <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
   <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>

    <f:view>

       <head></head>

       <body>

          <h:form>

             <h:panelGrid columns="3">

                <h:inputText value="#{bb.day}"   binding="#{bb.dayInput}" size="2" required="true"/>

                <h:inputText value="#{bb.month}" binding="#{bb.monthInput}" size="2" required="true"/>

                <h:inputText value="#{bb.year}"  binding="#{bb.yearInput}" size="4" required="true" validator="#{bb.validateDate}"/>

                <h:message for="year" styleClass="errorMessage"/>

             </h:panelGrid>

             <h:commandButton value="Submit" action="submit"/>

          </h:form>

       </body>

    </f:view>

 </html>

Reference: Core JavaServer™ Faces By DAVID GEARY, CAY HORSTMANN

Publisher : Addison Wesley Pub Date : June 15, 2004 ISBN : 0-13-146305-5

krmby