As
you probably know, PrimeFaces comes with a very useful support for client side
validation based on JSF validation API and Bean Validation. In this post we
will focus on Bean Validation, and say that this can be successfully used as
long as we don't need cross-field validation or class level validation. This
means that the validation constrains placed at class level will not be
recognized by PrimeFaces client side validation.
In
this post, you can see a pretty custom solution, but pretty fast to implement in order to obtain a cross-field client side validation for Bean Validation using PrimeFaces. We
have a user contact made of a name and an e-mail, and our validation constraint
is of type: e-mail must start with name (e.g. name@domain.com):
<h:form>
<p:panelGrid columns="3">
<p:outputLabel for="nameId"
value="Name"/>
<p:inputText id="nameId"
value="#{contactBean.name}"/>
<p:message for="nameId"/>
<p:outputLabel for="emailId"
value="E-mail"/>
<p:inputText id="emailId"
value="#{contactBean.email}"/>
<p:message
for="emailId"/>
<p:commandButton value="Contact
Member" action="#{contactBean.someAction()}"
update="@form"
validateClient="true"/>
</p:panelGrid>
<p:messages/>
</h:form>
For
accomplishing this task, we will slightly adapt the PrimeFaces custom client
side validation.
First,
we create ValidContact annotation:
@Documented
@Constraint(validatedBy
= {ContactValidator.class})
@ClientConstraint(resolvedBy=ValidContactClientConstraint.class)
@Target({ANNOTATION_TYPE,
METHOD, FIELD})
@Retention(RUNTIME)
public
@interface ValidContact {
String message() default "Invalid contact
!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload()
default {};
}
Further,
in our bean we annotate the proper fields (name and email) with this annotation - we need to do this to
indicate the fields that enters in cross-field validation; so, annotate each
such field:
@Named
@RequestScoped
public class
ContactBean implements Serializable {
private static final long serialVersionUID =
1L;
@ValidContact(message = "The name should
be used in e-mail as name@domain.com!")
private String name;
@ValidContact(message = "The e-mail
should be of type name@domain.com!")
private String email;
// getters and setters
public void someAction() {
Messages.addGlobalInfo("Thank you for
your contacts!");
}
}
Now,
we write the validator. Here, we need to keep the name until the validator gets
the e-mail also. For this, we can use the faces context attributes, as below:
public class
ContactValidator implements ConstraintValidator<ValidContact, String> {
@Override
public void initialize(ValidContact
constraintAnnotation) {
// NOOP
}
@Override
public boolean isValid(String value,
ConstraintValidatorContext context) {
if
(Faces.getContextAttribute("NAME_VALUE") == null) {
Faces.setContextAttribute("NAME_VALUE",
value);
} else
{
return
value.startsWith(String.valueOf(Faces.getContextAttribute("NAME_VALUE")));
}
return true;
}
}
Now,
we have to accomplish the client-side validation. Again, notice that we store
the name into an array (you can add here more fields) and wait for the e-mail:
<script
type="text/javascript">
var data = [];
PrimeFaces.validator['ValidContact'] = {
MESSAGE_ID:
'org.primefaces.examples.validate.contact.message',
validate:
function (element, value) {
if (data.length == 0) {
data.push(value);
} else {
if (!value.startsWith(data[0])) {
var msgStr =
element.data('p-contact-msg'),
msg = msgStr ? {summary: msgStr, detail:
msgStr} :
vc.getMessage(this.MESSAGE_ID);
throw msg;
}
}
}
};
</script>
Finally,
we ensure the presence of ClientValidationConstraint
implementation:
public class
ValidContactClientConstraint implements ClientValidationConstraint {
public static final String MESSAGE_METADATA =
"data-p-contact-msg";
public Map<String, Object>
getMetadata(ConstraintDescriptor constraintDescriptor) {
Map<String, Object> metadata = new
HashMap<String, Object>();
Map attrs =
constraintDescriptor.getAttributes();
Object message =
attrs.get("message");
if (message != null) {
metadata.put(MESSAGE_METADATA, message);
}
return metadata;
}
public String getValidatorId() {
return
ValidContact.class.getSimpleName();
}
}
Valid screenshot:
Invalid screenshot:
Done!
The complete application is available here.
Read more such goodies in:
Read more such goodies in:
Niciun comentariu :
Trimiteți un comentariu