15

I'm trying to validate two password fields with JSF but no good until now, I search for it on google but everything was about JSF 1.2 and pretty confusing, I'm using JSF 2.0.

This is what I'm doing so far:

        <h:outputLabel for="password" value="Password:" />
        <h:inputSecret id="password"  value="#{register.user.password}"  >  
            <f:ajax    event="blur"   listener="#{register.validatePassword}" render="m_password" />
        </h:inputSecret>
        <rich:message id="m_password" for="password"/>

        <h:outputLabel for="password_2" value="Password (again):" />
        <h:inputSecret id="password_2"  value="#{register.user.password_2}"  >  
            <f:ajax    event="blur"     listener="#{register.validatePassword}" />
        </h:inputSecret>

This is how I it is my controller:

public void validatePassword() {
    FacesMessage message;

    if (!user.getPassword().equals(user.getPassword_2()) ){
        message = new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "different password");
    }else{
        message = new FacesMessage(FacesMessage.SEVERITY_INFO, null, "ok");
    }

    FacesContext.getCurrentInstance().addMessage("form:password", message);
}

Any idea guys ?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Valter Silva
  • 16,446
  • 52
  • 137
  • 218
  • What do you mean it is working but not so good? Is it slow? Not sure I understand what you want to change and why. – jdias Sep 20 '11 at 18:41
  • Hi @jdias, I mean is not working the way it suppose to be. Thanks for that could be a bit confusing. – Valter Silva Sep 20 '11 at 19:51

3 Answers3

19

First of all, use a real Validator to validate the input. Don't do it in an action event method.

As to your concrete problem, you just need to specify the both fields in the execute attribute of the <f:ajax>, it namely defaults to the current component only. If you attach a validator to the first input and send the the value of the second input along as a <f:attribute>, then you will be able to grab it in the validator. You can use the binding attribute to bind the component to the view. This way you can pass its submitted value along by UIInput#getSubmittedValue().

Here's a kickoff example:

<h:outputLabel for="password" value="Password:" />
<h:inputSecret id="password" value="#{bean.password}" required="true">
    <f:validator validatorId="confirmPasswordValidator" />
    <f:attribute name="confirm" value="#{confirmPassword.submittedValue}" />
    <f:ajax event="blur" execute="password confirm" render="m_password" />
</h:inputSecret>
<h:message id="m_password" for="password" />

<h:outputLabel for="confirm" value="Password (again):" />
<h:inputSecret id="confirm" binding="#{confirmPassword}" required="true">
    <f:ajax event="blur" execute="password confirm" render="m_password m_confirm" />
</h:inputSecret>
<h:message id="m_confirm" for="confirm" />

(note that I added required="true" to both components and also note that you don't necessarily need to bind the confirm password component value to a managed bean property, it's worthless over there anyway)

with this validator

@FacesValidator("confirmPasswordValidator")
public class ConfirmPasswordValidator implements Validator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        String password = (String) value;
        String confirm = (String) component.getAttributes().get("confirm");

        if (password == null || confirm == null) {
            return; // Just ignore and let required="true" do its job.
        }

        if (!password.equals(confirm)) {
            throw new ValidatorException(new FacesMessage("Passwords are not equal."));
        }
    }

}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • what's confirmPassword in binding="#{confirmPassword}" ? – Mahmoud Saleh Sep 22 '11 at 15:53
  • 1
    @Jsword: it will bind the component to the view by exactly the given identifier so that it's available by `#{confirmPassword}` elsewhere in the view (such as in `` of the first field so that it can be obtained in validator). – BalusC Sep 22 '11 at 16:06
  • I understand now the function of 'binding' BalusC, thanks for the help dude. – Valter Silva Sep 24 '11 at 00:06
  • You're welcome. You can by the way also bind it to a bean property. It would then be an `UIInput` property. But that's not necessary in this case (and it would break viewscoped beans). – BalusC Sep 24 '11 at 00:07
0

You can use Primefaces p:password tag. Please see demo example. It has match attribute which should be the id of confirm password.

<p:panel header="Match Mode">  
    <p:messages id="messages" showDetail="true" autoUpdate="true"/>  

    <h:panelGrid columns="2" id="matchGrid">                     
                <h:outputLabel for="pass" value="Password " />  
                <p:password id="pass" value="#{passwordBean.password}" match="confirmPass"   required="true"/>  

                <h:outputLabel for="confirmPass" value="Confirm Password " />  
                <p:password id="confirmPass" value="#{passwordBean.confirmPassword}" required="true"/>  
    </h:panelGrid>  

    <p:commandButton id="saveButton" update="matchGrid" value="Save" />  
</p:panel>
Vahe Harutyunyan
  • 652
  • 2
  • 10
  • 17
0

With seam 2 you have the component <s:validateEquality> and you don't need to write code. For JSF2 then you have Seam 3 modules, particulary Faces module and Cross-field Form Validation. An example :

First you have to use the s:validateForm tag:

<h:form id="passwordForm">
    <h:inputSecret id="newPassword"
        required="true"
        redisplay="true"
        value="#{passwordController.newPassword}">
    </h:inputSecret>            
    <h:inputSecret id="confirmationPassword"
        value="#{passwordController.confirmPassword}"
        required="true"
        redisplay="true">
    </h:inputSecret>
    <h:commandButton id="submit" value="Submit" action="#{passwordController.submitPassword}" />
    <s:validateForm validatorId="passwordValidator" />
</h:form>

and the corresponding Validator for the password form above would look like this:

@FacesValidator("PasswordValidator")
public class PasswordValidator implements Validator
{
   @Inject
   @InputField
   private String newPassword;

   @Inject
   @InputField
   private String confirmPassword;

   @Override
   public void validate(final FacesContext context, final UIComponent comp, final Object values) throws ValidatorException
   {
      if (!confirmPassword.equals(newPassword))
      {
         throw new ValidatorException(new FacesMessage("Passwords do not match!"));
      }
   }
}
Victor Martinez
  • 1,102
  • 2
  • 8
  • 22
  • I looked for a similar solution in pure JSF2, but I couldn't find it. Do you know if this exists in JSF2? Especially the @InputField annotation seems useful. – Jurgen Hannaert Feb 24 '12 at 07:29