RichFaces 4 - Client Side Validation

Posted by    |      

Introduction

One great feature in JSF 2 is that it provides built-in support for JSR-303 bean validators. This means that now it is the containers responsibility to validate your model objects at multiple application tiers according to your annotation based constraints. Take a look at a simple JSF managed bean with JSR-303 annotations added:

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

@ManagedBean
@RequestScoped
public class UserBean {

    @Size(min=3, max=12)
    private String name = null;
    @Pattern(regexp = "^[\\w\\-]([\\.\\w])+[\\w]+@([\\w\\-]+\\.)+[a-zA-Z]{2,4}$" , message="Bad email")
    private String email = null;
    @Min(value = 18)
    @Max(value = 99)
    private Integer age;
///...
//Getters and Setters
}

With JSF 2 all the validators added using bean validation annotations will be registered on components bound to the bean properties and triggered in the Process Validation phase. So you have no need to define additional validators using JSF standard validator tags such as f:validateLength or f:validateDoubleRange or use the required attribute. But all that stuff is applied only on the server side. In the past you needed to create some custom validators for client side which are not connected to server side rules directly but just copies that functionality. This of coarse leads to additional maintenance and complexity.

Now with RichFaces 4 we provide that final level of abstraction to the validation ecosystem. RichFaces Client Side Validation feature(CSV abbreviation used across wiki pages and jiras) consist of:

  • JavaScript validators implementations for nearly all JSF and JSR-303 validators.
  • Mechanism which register corresponding client validators to the components which bound to annotated fields or uses f:validate* attached.
  • rich:message(s) components were added with client side objects which allows to manipulate with them on client side. Used to add/remove messages which appeared at client side.
  • Extension points which allows the user to provide JavaScript implementation for his custom server side validators (in the future).

Usage

First need to mention a common requirement for both JSF and RichFaces using bean validation. In order to use it with JSF 2 - you should use JEE 6 application server which is bundled with a JSR-303 implementation. Or if using just Tomcat or another simple servlet container add validation-api jar and some validators provider (e.g. hibernate-validator) to your application libraries.

Then all you need to add to the component in order it to start using client validators is new rich:validator behavior:

<h:inputText value="#{userBean.name}">
	<rich:validator/>
</h:inputText>
@Size

constraint rules defined in UserBean above will be applied there. Or you can use a similar definition for old-style JSF validators:

<h:inputText value="#{personBean.name}">
	<f:validateLength minimum="3"/>
	<rich:validator/>
</h:inputText>

Client implementation of Length validator will be registered to be called on the client.

Note: You still could use JSF validators tags but it's really preferable to migrate to Bean Validation. As you can see from that sample you still duplicating the validation at view and model level using annotation based constraints for your entities and defining the same view validators with separate tags.

<rich:validator> is a behavior which just triggers all the client validators methods according to the registered server side validators. As a behavior it could be defined for any event available on parent component. In previous examples default event change used. Let's modify examples to use keyup event:

<h:inputText value="#{userBean.name}">
	<rich:validator event="keyup"/>
</h:inputText>

Ajax Fall-back

In case you registered some validators but they have no client implementation available — Ajax fall-back will be used. This means that <rich:validator> will invoke all the available client validators. And if all of them returned valid, RichFaces will perform an Ajax request invoking any server side validators.

Note: For now Ajax fall-back is always used if a client validator is not available. In future we planned to design some way to invoke only available client validators and not send Ajax request for the others RF-10142. Could be useful in some cases where additional request to server are not expected because validators uses some complex services invocations or makes db calls for example.

Messages from client validators

And the last question is - how do users get notified with the client side validation results? It's rather simple actually. Messages for client validators will be displayed using the same rich:message(s) components which are used for common server side validation messages.

So let's review complete sample for the Edit user info form:

<h:form>
<rich:panel header="User information">
	<h:panelGrid columns="3"> 
		<h:outputText value="Name:" />
		<h:inputText value="#{validationBean.name}" id="name">
			<rich:validator />
		</h:inputText>
		<rich:message for="name" />
		<h:outputText value="Email" />
		<h:inputText value="#{validationBean.email}" id="email">
			<rich:validator />
		</h:inputText>
		<rich:message for="email" />
		<h:outputText value="Age" />
		<h:inputText value="#{validationBean.age}" id="age">
			<rich:validator />
		</h:inputText>
		<rich:message for="age" />
		<h:outputText value="I agree the terms" />
		<h:selectBooleanCheckbox value="#{validationBean.agree}" id="agree">
			<rich:validator/>
		</h:selectBooleanCheckbox>
		<rich:message for="agree" />
	</h:panelGrid>
</rich:panel>
</h:form>

in case of failure of any validator registered to name h:inputText component - message below will be updated by CSV JavaScript showing the information label. Here is the screenshot from richfaces-showcase application:

All the messages for inputs appeared without any server side validation invocation. Script validation invoked after you changed the field and shifting focus out of the component. In this case only one Ajax request was sent – after clicking the check-box (AssertTrue validator client implementation is not available for M6 actually so you see Ajax fall-back in action). Pretty easy isn't it?

M6 functionality

In RichFaces 4 Milestone 6 all the server side functionality related to registered validators look-up, validators script output, messages and behavior rendering were done. As for client side functionality – all messages, JSF validators and most of JSR-303 validators are complete. We have a few validators still missing (e.g. AssertTrue/False, Past) but they will be added in nearest time. See developer richfaces-showcase demo which was added with CSV samples prior to M6.

Note: As it was mentioned before missed validators will be invoked using Ajax fall-back.

Start Using Now

Even considering some minor issues reported and a few validators still missed – it's worth to start using the CSV right now. You will need to do nothing in the future in order for new validators to start working once they are implemented. When you update to next version they will be automatically added by behavior script renderer and start working on the client side. Also, you can help let us know about any problems or concerns prior to final.

The future plans for validation

  • Add default levels of validation support. This means that we will provide an option that will enable <rich:validator> automatically at some level such as for a form or view.
  • Add support to Action components. This means that you will be able to add <rich:validator> to your "save" form button and it will call all the validators for inputs in the form prior to submit.
  • Complete instructions for creation custom validators. Basic mechanisms is ready so we just need to check how it will works and document.

[Get updates of my blogs in twitter]

[My jroller.com blog]


Back to top