I took the following BalusC kickoff example and modified it a bit by adding a submit button and additional h:messages and removing the f:ajax
from the h:inputSecret's
(removed the f:ajax
cause for some reason when I leave the first h:inputSecret
it immediately displays "value is required" error for the second h:inputSecret
- but the user haven't got the chance to type it in... ??? <- another future question ?:) )
OK, to make long story short:
I'm trying to figure out how can display the validation errors regarding the both password fields(that the passwords are not equal) in the global h:messages and not in the individual h:message of the password fields
I do want that the required="true" will be displayed in the <h:message
of each field...
But right now the validation message (thrown by my exception) and the required="true" are being displayed in the same place
Here is the code:
<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}" />
</h:inputSecret>
<h:message id="m_password" for="password" />
<h:outputLabel for="confirm" value="Password (again):" />
<h:inputSecret id="confirm" binding="#{confirmPassword}" required="true">
</h:inputSecret>
<h:message id="m_confirm" for="confirm" />
And additional h:commandButton
with h:messages
below that code :
<h:commandButton value="doSomething" action="#{myBean.myAction}">
<f:ajax execute="password confirm" render="m_password m_confirm"></f:ajax>
</h:commandButton>
<h:messages globalOnly="true" styleClass="validation_value_required"/>
@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."));
}
}
}
Also
Thanks ahead,
Solution (Thanks to BalusC)
changed
<f:attribute name="confirm" value="#{confirmPassword.submittedValue}" />
to
<f:attribute name="confirm" value="#{confirmPassword}" />
and
String confirm = (String) component.getAttributes().get("confirm");
into
UIInput confirmPasswordComponent = (UIInput) component.getAttributes().get("confirm");
String confirm = (String) confirmPasswordComponent.getSubmittedValue();
and
throw new ValidatorException(new FacesMessage("Passwords are not equal."));
into
context.addMessage(null, new FacesMessage("Passwords are not equal."));
context.validationFailed();
((UIInput) component).setValid(false);
confirmPasswordComponent.setValid(false);
return;
If a Validator
on a particular component throws a ValidatorException
, then its FacesMessage
will automatically be associated with the component on which the Validator
is invoked.
You need to manually add the FacesMessage
on a null
client ID so that it end up in <h:messages globalOnly="true">
. You also need to manually set validationFailed()
on FacesContext
so that JSF won't update the model values nor invoke the action. If necessary (though recommended), you also need to manually mark the components as invalid so that any appropriate listeners/tree-visitors (e.g. for highlighting) will take this into account.
if (!password.equals(confirm)) {
context.addMessage(null, new FacesMessage("Passwords are not equal."));
context.validationFailed();
((UIInput) component).setValid(false);
confirmPasswordComponent.setValid(false); // You'd need to pass it as component instead of as its submitted value in f:attribute.
}
By the way, the OmniFaces project has an <o:validateEqual>
component which should make this less tedious. See also showcase example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With