My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

luni, 25 ianuarie 2016

PrimeFaces cross-field client bean validation sample

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:

PrimeFaces & OmniFaces - Powers Combined

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors