Java Server Faces (JSF) is a component-oriented framework for building web application using Java. JSF makes it easy to build web application by automating common tasks such as populating input parameter values into Java Beans by parsing input parameters, performing validations, and rendering or updating views. But building web application with rich User Interfaces (UI) still remains a challenge as Java developers may or may not be good at building fancy UI components using HTML, JavaScript directly. As JSF is a component-based framework, it allows building custom UI components with rich look and feel and can be reusable in any project.
The good news is that there are many open source and proprietary frameworks providing readymade reusable UI components, which can be used in any JSF-based applications. Among the several UI component libraries available today, PrimeFaces is an outstanding UI component library in terms of features and ease of use.
In this chapter, we will cover:
Introducing the features of PrimeFaces
Installing and configuring PrimeFaces
Creating a HelloWorld application using PrimeFaces
Creating simple forms using PrimeFaces
Performing form validations
Performing client-side validations
Understanding partial page rendering (PPR)
Updating view using AJAX
Updating view using AJAX listeners
Performing tasks periodically using the poll component
Invoking server-side methods from JavaScript using RemoteCommand
In this chapter, we will see what features make PrimeFaces an outstanding library, how to install and configure PrimeFaces and start using some of its basic components.
PrimeFaces is an open source JSF component library with 100+ rich UI components support. It has built-in AJAX support based on standard JSF 2.0 AJAX APIs.
PrimeFaces provides the following set of features, which makes it powerful UI component library yet easy to use:
More than 100 rich UI components
Built-in AJAX support
Zero configurations
Does not require any third-party library dependencies for most of the components
Integrated with ThemeRoller
30+ readily available themes
Supports IE8+, Chrome, Firefox, Safari, and Opera browsers
The PrimeFaces library comes as a single jar file and doesn't have any mandatory third-party library dependencies. So to use PrimeFaces, it is sufficient to add PrimeFaces jar along with a JSF implementation library such as Oracle's Mojarra or Apache's MyFaces.
However, based on the PrimeFaces features that you want to use, you may need to add some third-party libraries. The following table describes library dependency needed for a particular feature:
Dependency |
Type |
Version |
Description |
---|---|---|---|
JSF runtime |
2.0, 2.1, or 2.2 |
Required |
Apache MyFaces or Oracle Mojarra |
itext |
2.1.7 |
Optional |
DataExporter (PDF) |
apache poi |
3.7 |
Optional |
DataExporter (Excel) |
rome |
1.0 |
Optional |
FeedReader |
commons-fileupload |
1.2.1 |
Optional |
FileUpload |
commons-io |
1.4 |
Optional |
FileUpload |
The preceding table contains the third-party library versions, which are tested and known to be working fine with PrimeFaces-4.0 version. Other versions might also work fine but they are not officially tested.
Tip
If you are using a servlet container such as Apache Tomcat, then you need to add JSF implementation library dependencies such as Oracle's Mojarra or Apache MyFaces. If you are using any JavaEE application servers such as, JBoss AS, Glassfish, WebLogic, and so on; then there is no need to add JSF implementation libraries explicitly as they come in-built with application server. Some application servers may not have latest JSF implementation libraries. So, check whether your application server has JSF 2.0 or 2.1 or 2.2 implementation libraries or not. Consult your application server specific documentation to see how to override server libraries with latest versions.
In this book, we will be using PrimeFaces-4.0, which is latest version at the time of writing along with Oracle's Mojarra-2.2.3 JSF implementation.
Perform the following steps to install and configure PrimeFaces to your web application:
Configure JSF FacesServlet in
web.xml
:<servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping>
Tip
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
If you are not using Maven, then you can download
PrimeFaces-4.0.jar
from http://www.primefaces.org/downloads.html and add it to classpath.If you are using Maven, then add PrimeFaces maven repository to the repository list, and add PrimeFaces-4.0 dependency in
pom.xml
.<repository> <id>prime-repo</id> <name>Prime Repo</name> <url>http://repository.primefaces.org</url> </repository> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-impl</artifactId> <version>2.2.3</version> </dependency>
We have configured PrimeFaces repository and primefaces-4.0.jar
dependency in our maven pom.xml
, so that the PrimeFaces library is available to the web application classpath. We have configured FacesServlet and mapped to the URL pattern *.jsf
, other popular URL patterns used are /faces/*
, *.faces
, and *.xhtml
.
In previous section, we have configured and installed PrimeFaces. To start using PrimeFaces components, all we need to do is adding the namespace xmlns:p=http://primefaces.org/ui
to JSF pages.
Let us create a simple JSF page using PrimeFaces to see whether we have successfully installed and configured PrimeFaces.
Let us create a helloworld.xhtml
file with the PrimeFaces namespace configuration, and use the PrimeFaces editor component to display a rich HTML editor. Perform the following steps:
To start using PrimeFaces components all we need to do is add the namespace
xmlns:p=http://primefaces.org/ui
in JSF facelets page.<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui"> <f:view contentType="text/html"> <h:head> <title>First PrimeFaces Page</title> </h:head> <body> <h:form> <p:editor value="Hello World, PrimeFaces Rocks!!"/> </h:form> </body> </f:view> </html>
Run the application and point your browser to
http://localhost:8080/chapter01/helloworld.jsf
. We can see the rich text editor as follows:
We have tested PrimeFaces configuration by using PrimeFaces editor component <p:editor/>
. As we have configured PrimeFaces properly, we are able to see rich HTML editor.
Make sure you have the
<h:head>
tag in your facelets page to avoid "PrimeFaces not found" JavaScript error.To make PrimeFaces work properly on webkit layout engine-based browsers such as, Chrome/Safari, enforce
contentType
to text/html using<f:view contentType="text/html">
.
PrimeFaces provides various input elements such as inputText
, password
, inputTextarea
, commandButton
, commandLink
, and so on, which are extensions to the standard JSF components providing additional features and theming support.
To get a feel of how to use PrimeFaces components, let us create a simple user registration form using PrimeFaces components.
Let's start using PrimeFaces components by creating a simple user registration form, steps for the same are as follows:
Create a
User.java
POJO (Plain Old Java Object):public class User { private Integer id; private String userName; private String password; private String firstName; private String lastName; private String email; private String phone; //setters & getters }
Create a JSF managed bean
UserController.java
, using the following code:@ManagedBean @RequestScoped public class UserController { private User registrationUser; public UserController() { this.registrationUser = new User(); } public User getRegistrationUser() { return registrationUser; } public void setRegistrationUser(User registrationUser) { this.registrationUser = registrationUser; } public String register() { System.out.println("Register User :"+ this.registrationUser); String msg = "User Registered Successfully"; FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg)); FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(true); return "registration.jsf?faces-redirect=true"; } }
Create a
registration.xhtml
page to build the user registration form using PrimeFaces components as follows:<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui"> <h:head> <title>Registration</title> </h:head> <body> <h:form id="registrationForm"> <p:panel header="Registration Form" style="width: 500px;"> <p:messages/> <h:panelGrid columns="2"> <p:outputLabel value="UserName:"/> <p:inputText id="userName" value="#{userController.registrationUser.userName}" label="UserName" /> <p:outputLabel value="Password:"/> <p:password id="password" value="#{userController.registrationUser.password}" label="Password"/> <p:outputLabel value="FirstName:"/> <p:inputText id="firstName" value="#{userController.registrationUser.firstName}" label="FirstName"/> <p:outputLabel value="LastName:"/> <p:inputText id="lastName" value="#{userController.registrationUser.lastName}"/> <p:outputLabel value="Email:"/> <p:inputText id="email" value="#{userController.registrationUser.email}"/> <p:outputLabel value=""/> <p:commandButton action="#{userController.register}" value="Register" update="registrationForm"/> </h:panelGrid> </p:panel> </h:form> </body> </html>
Run the application and point your browser to
http://localhost:8080/chapter01/registration.jsf
. Then you can see the following screenshot, Registration Form:
We have created a sample user registration form using PrimeFaces UI components <p:inputText/>
, <p:password/>
, <p:commandButton/>
, and so on. We are looking for input components with rich look and feel because we used PrimeFaces components, which are extensions to the standard JSF UI components with theming support.
Validating user submitted data is very common and a crucial part of any web application. JSF itself provides support for UI component validation and PrimeFaces enhances it with additional features.
In the previous section, we have created a sample user registration form but we did not validate the form for any mandatory fields. Let us enhance the registration form with the validations for mandatory fields.
Assume we have the following validation rules for the registration form:
UserName
should not be blank.Password
should not be blank and should be at least four characters.FirstName
should not be blank.
We can use JSF validations for performing the earlier mentioned validations on the registration form. We can also perform validations using PrimeFaces AJAX-based validations by hooking up with JavaScript events, for this perform the following steps:
Update
registrationWithVal.xhtml
to build a user registration form along with validation support using the following code:<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui"> <h:head> <title>Registration</title> </h:head> <body> <h:form id="registrationForm"> <p:panel header="Registration Form" style="width: 800px;"> <p:messages /> <h:panelGrid columns="3"> <p:outputLabel value="UserName:*"/> <p:inputText id="userName" value="#{userController.registrationUser.userName}" required="true" label="UserName" > <p:ajax event="keyup" update="userNameMsg"/> </p:inputText> <p:message id="userNameMsg" for="userName"/> <p:outputLabel value="Password:*"/> <p:password id="password" value="#{userController.registrationUser.password}" required="true" label="Password"> <f:validateLength minimum="4"/> <p:ajax update="passwordMsg" event="keyup"/> </p:password> <p:message id="passwordMsg" for="password"/> <p:outputLabel value="FirstName:*"/> <p:inputText id="firstName" value="#{userController.registrationUser.firstName}" required="true" label="FirstName"> </p:inputText> <p:message id="firstNameMsg" for="firstName"/> <p:outputLabel value="LastName:"/> <p:inputText id="lastName" value="#{userController.registrationUser.lastName}"/> <p:message id="lastNameMsg" for="lastName"/> <p:outputLabel value="Email:"/> <p:inputText id="email" value="#{userController.registrationUser.email}"/> <p:message id="emailMsg" for="email"/> <p:outputLabel value=""/> <p:commandButton action="#{userController.register}" value="Register" update="registrationForm"/> <p:outputLabel value=""/> </h:panelGrid> </p:panel> </h:form> </body> </html>
Run the application and point your browser to
http://localhost:8080/chapter1/registrationWithVal.jsf
. LeaveUserName
andFirstName
blank and enterpassword
with less than four characters and submit the form. Then Registration Form will be redisplayed with errors as shown in the following screenshot:
We have used input validations such as required, minimum length, and so on. We have used PrimeFaces AJAX-based validations using <p:ajax>
on the keyup
JavaScript event. So as you type in the password
, it will get validated and update the validation message immediately. You can also use <p:ajax>
with other JavaScript events such as keydown
, keypress
, mouseover
, and so on.
In our Registration Form, we can do some basic e-mail format validation on client side itself thereby reducing the server roundtrip. We can create a JavaScript function to validate e-mail using Regex, and then hook it up with the onchange
event on e-mail input field. Perform the following steps for the same:
Write a JavaScript function to validate e-mail address:
function validateEmail() { var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/; var email = $.trim($("#userForm\\:email").val()); if(email ==''){ $("#userForm\\:emailMsg").text(""); $("#userForm\\:emailMsg").attr("class", ""); return; } if( emailReg.test( email ) ) { $("#userForm\\:emailMsg").text("Valid Email"); $("#userForm\\:emailMsg").attr("class", "ui-messages-info ui-widget ui-corner-all ui-messages-info-summary"); } else { $("#userForm\\:emailMsg").text("Invalid Email"); $("#userForm\\:emailMsg").attr("class", "ui-message-error ui-widget ui-corner-all ui-message-error-detail"); } }
Add the
validateEmail()
function as an event handler for theonchange
event on the e-mail input field:<h:form id="userForm"> <p:outputLabel value="Email:"/> <p:inputText id="email" value="#{userController.user.email}" onchange="validateEmail();" /> <p:message id="emailMsg" for="email"/> </h:form>
We have created a JavaScript function to validate e-mail using Regex. Using the jQuery API we have added an info/error message notifying us whether the e-mail is valid or invalid. We have hooked up this function to the onchange
event of the e-mail inputText
element. So validateEmail()
gets invoked as soon as the e-mail value is changed and shows the message.
We got the e-mail field using $("#userForm\\:email")
, where userForm
is the ID of the form and email
is the ID of the e-mail inputText
field. JSF generates the IDs with colon (:) separator, but jQuery has a special meaning for colon .So we have replaced the colon (:) with \\
:
Instead of replacing the colon by yourself, you can use the PrimeFaces.escapeClientId()
utility function as follows:
function validateEmail() { var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/; var email = $.trim($(PrimeFaces.escapeClientId("userForm:email")).val()); if(email ==''){ $(PrimeFaces.escapeClientId("userForm:emailMsg")).text(""); $(PrimeFaces.escapeClientId("userForm:emailMsg")).attr("class", ""); return; } if( emailReg.test( email ) ) { $(PrimeFaces.escapeClientId("userForm:emailMsg")).text("Valid Email"); $(PrimeFaces.escapeClientId("userForm:emailMsg")).attr("class", "ui-messages-info ui-widget ui-corner-all ui-messages-info-summary"); } else { $(PrimeFaces.escapeClientId("userForm:emailMsg")).text("Invalid Email"); $(PrimeFaces.escapeClientId("userForm:emailMsg")).attr("class", "ui-message-error ui-widget ui-corner-all ui-message-error-detail"); } }
Tip
Since JSF2.x, we can also change the JSF ID separator character using the following <context-param>
configuration in web.xml
:
<context-param> <param-name>javax.faces.SEPARATOR_CHAR</param-name> <param-value>-</param-value> </context-param>
The preceding client-side validation process involves performing manual validations using JavaScript/jQuery. PrimeFaces-4.0 introduced the Client Side Validation (CSV) framework with more powerful features, which we will discuss in Chapter 4, Introducing the PrimeFaces Client Side Validation Framework.
PrimeFaces provides a generic partial page rendering (PPR) mechanism to update specific JSF components with AJAX.
PrimeFaces provides process, update
attributes to indicate which view components need to be processed or updated. Partial processing also provides some keywords which has some special meaning.
Keyword |
Description |
---|---|
|
Component that triggers the PPR is processed. |
|
Parent of the PPR trigger is processed. |
|
Encapsulating form of the PPR trigger is processed. |
|
Encapsulating naming container. |
|
No component is processed, useful to revert changes to form. |
|
Whole component tree is processed just like a regular request. |
Sometimes, we may need to process the form partially based on the action triggered on the form. A very common scenario is, there can be multiple submit buttons in a form and you need to perform validations based on the action performed and ignore other field validations that are irrelevant to the action invoked.
For example, assume we are viewing a User Detail Form and we can update the user details or delete the user record using Update and Delete submit buttons. For updating, the user fields, userId
, userName
, and firstName
are mandatory where as for deleting, only userId
is required. So, when the Update button is clicked, validations should be performed on userId
, userName
, and firstName
fields. But when the Delete button is clicked, validations on userName
and firstName
should be skipped.
In this section, we will demonstrate how to process only a subset of components based on the action performed.
Create
userDetails.xhtml
with the User Details Form containing update and delete actions:<h:form id="userDetailsForm"> <p:panel header="User Details Form" style="width: 800px;"> <p:messages/> <h:panelGrid columns="3"> <p:outputLabel value="UserId:*"/> <p:inputText id="userId" value="#{userController.loginUser.id}" required="true" label="UserId" /> <p:message id="userIdMsg" for="userId"/> <p:outputLabel value="UserName:*"/> <p:inputText id="userName" value="#{userController.loginUser.userName}" required="true" label="UserName" /> <p:message id="userNameMsg" for="userName"/> <p:outputLabel value="Password:*"/> <p:password id="password" value="#{userController.loginUser.password}" required="true" label="Password"/> <p:message id="passwordMsg" for="password"/> <p:outputLabel value="FirstName:*"/> <p:inputText id="firstName" value="#{userController.loginUser.firstName}" required="true" label="FirstName"/> <p:message id="firstNameMsg" for="firstName"/> <p:commandButton value="Update" action="#{userController.updateUser()}" update="userDetailsForm"/> <p:commandButton value="Delete" action="#{userController.deleteUser()}" update="userDetailsForm"/> </h:panelGrid> </p:panel> </h:form>
Create a managed bean
UserController.java
to perform update and delete actions:@ManagedBean @RequestScoped public class UserController { private User loginUser; public UserController() { this.loginUser = new User(); } public User getLoginUser() { return loginUser; } public void setLoginUser(User loginUser) { this.loginUser = loginUser; } public String updateUser() { System.out.println("Updating User Id: "+this.loginUser.getId()); String msg = "User updated Successfully"; FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg)); return "userDetails.jsf"; } public String deleteUser() { System.out.println("deleting User Id: "+this.loginUser.getId()); String msg = "User deleted Successfully"; FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg)); return "userDetails.jsf"; } }
Run the application and point your browser to
http://localhost:8080/chapter01/userDetails.jsf
.
When you click on the Delete button, the whole form will be processed, and displays a form with error messages if any required fields are blank. To resolve this issue, we can use the process
attribute to specify only the UserId
field to be processed and invoke the deleteUser()
method:
<p:commandButton value="Delete"action="#{userController.deleteUser()}" process="@this,userId" update="userDetailsForm"/>
We have used the process
attribute to specify which components to be processed so that we can bypass the other fields' validations, which are irrelevant to the invoked action. Also note that <p:commandButton>
issues an AJAX request by default. So if you want to redirect to a different page after action logic is executed make it a non-AJAX request by setting ajax="false"
.
Both JSF AJAX implementation and PrimeFaces serializes the whole form data, and post it to server even for AJAX requests that will process only partial components. In the case of forms with more number of input components, we will be sending huge payload even though only few specific components will be processed on server side. This process unnecessarily consumes server resources.
PrimeFaces provides partialSubmit
feature, which enables to serialize and send only the components data that will be processed on server side. By default partialSubmit
feature is disabled, and we can enable this feature globally by configuring the following context parameter in web.xml
:
<context-param> <param-name>primefaces.SUBMIT</param-name> <param-value>partial</param-value> </context-param>
The preceding configuration enables partialSubmit
feature globally. We can override this partialSubmit
behavior for specific command components or AJAX events as follows:
<p:commandButton value="Delete" action="#{userController.deleteUser()}" process="@this,userId" partialSubmit="true" update="userDetailsForm"/> <p:inputText id="userName" value="#{userController.registrationUser.userName}" required="true" label="UserName"> <p:ajax event="keyup" listener="#{userController.checkUserNamesExists()}" update="userNameMsg" partialSubmit="true"/> </p:inputText>
You can see the difference between payload data sending to server when partialSubmit
is enabled and disabled using firebug or chrome developer tools.
AJAX support became a must for any framework or library used for building rich and interactive web applications. AJAX features make the web application more responsive by updating parts of the page without requiring full page reload.
PrimeFaces has in-built AJAX support and is based on JSFs server-side APIs. On client side, PrimeFaces use the most popular JavaScript library jQuery.
Processing a form submission and updating the portions of view using AJAX is very commonly used feature in web applications. Let us see how we can submit a form and update the view using AJAX.
Let us create a Login Form with user name and password. When form is submitted, show the login status using AJAX. Perform the following steps for the same:
Create a
login.xhtml
page with login form as follows:<h:form id="loginForm"> <p:panel header="Login Form" style="width: 500px;"> <h:panelGrid columns="2"> <p:outputLabel value="UserName"/> <p:inputText value="#{userController.loginUser.userName}"/> <p:outputLabel value="Password"/> <p:password value="#{userController.loginUser.password}"/> <p:commandButton action="#{userController.login}" value="Login" update="loginStatusMsg"/> <p:commandButton type="reset" value="Reset"/> <p:outputLabel value="#{userController.loginStatus}" id="loginStatusMsg"/> </h:panelGrid> </p:panel> </h:form>
Create a
UserController.java
managed bean as follows:@ManagedBean @RequestScoped public class UserController { private User loginUser; private String loginStatus; public UserController() { this.loginUser = new User(); } public User getLoginUser() { return loginUser; } public void setLoginUser(User loginUser) { this.loginUser = loginUser; } public String getLoginStatus() { return loginStatus; } public void setLoginStatus(String loginStatus) { this.loginStatus = loginStatus; } public String login() { boolean validCredentials = "admin".equals(loginUser.getUserName()) && "admin".equals(loginUser.getPassword()); this.loginStatus = validCredentials? "Login Successful" : "Login failed"; return null; } }
Point the browser to
http://localhost:8080/chapter01/login.jsf
.
When you enter UserName and Password and click on the Login button, the login status should be displayed using AJAX. Have a look at the following screenshot:
We have created a
Login Form with UserName and Password fields. When we submit the form, the model gets updated and login status will be set based on the provided credentials. As we have specified to update the view component with the ID loginStatusMsg
through update="loginStatusMsg"
, when you click on the Login button, the login status will be displayed without complete page refresh.
Sometimes we may need instant feedback to be shown as and so user fills the form, instead of showing error messages after form submission. For example, in user Registration Form, we may want to check whether the UserName is already in use and show an error message immediately.
PrimeFaces provides AJAX listener support to invoke method on JSF managed bean. We can use this feature to check whether the entered UserName is already in use or not, and update the view to show error message using AJAX, even before submitting the entire form.
Let's add AJAX event listener keyup
event to the UserName input field so that as you type, it will check if the username entered is already in use or not.
Create
viewAjaxListener.xhtml
with registration form to validate the UserName using AJAX Listener as follows:<h:form id="registrationForm"> <p:panel header="Registration Form" style="width: 800px;"> <h:panelGrid columns="3"> <p:outputLabel value="UserName:*"/> <p:inputText id="userName" value="#{userController.registrationUser.userName}" required="true" label="UserName"> <p:ajax event="keyup" listener="#{userController.checkUserNamesExists()}" update="userNameMsg"/> </p:inputText> <p:message id="userNameMsg" for="userName"/> <p:outputLabel value="Password:*"/> <p:password id="password" value="#{userController.registrationUser.password}" required="true" label="Password"/> <p:message id="passwordMsg" for="password"/> <p:outputLabel value="FirstName:*"/> <p:inputText id="firstName" value="#{userController.registrationUser.firstName}" required="true" label="FirstName"/> <p:message id="firstNameMsg" for="firstName"/> <p:commandButton action="#{userController.register}" value="Register" update="registrationForm"/> </h:panelGrid> </p:panel> </h:form>
Create a
UserController.java
managed bean with thecheckUserNamesExists()
method to check whether the entered UserName is already in use or not and add the error message accordingly:public void checkUserNamesExists() { String userName = this.registrationUser.getUserName(); if("admin".equals(userName) || "test".equals(userName)) { String msg = "UserName ["+userName+"] already in use."; FacesContext.getCurrentInstance().addMessage("registrationForm:userName", new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg)); } }
Point your browser to
http://localhost:8080/chapter01/viewAjaxListener.jsf
.
Enter admin
or test
in the UserName field then you should see the error message displayed immediately as in the following screenshot:
We have used AJAX listener in conjunction with keyup
event on the UserName input field. So for each keyup
event the callback method checkUserNamesExists()
will be invoked to check whether the entered UserName value is admin
or test
, and adds error message if it is. As we are updating the view component with ID userNameMsg
using update="userNameMsg"
, the error message is displayed immediately using the AJAX update.
PrimeFaces provides poll component, which can be used to perform actions via JSF managed bean methods, periodically on regular intervals.
Suppose we want to display current time on web pages. We can do it by using poll component. We can update the currentTime
view component using <p:poll>
component to display current time for every second without reloading the entire page.
Let's display live time by polling server time for every second and display it using the poll component.
Create
poll.xhtml
with a poll component to displaycurrentTime
as follows:<h:form> <p:outputLabel value="Current Time:" /> <p:outputLabel id="currentTime" value="#{serverTimeBean.time}"/> <p:poll interval="1" listener="#{serverTimeBean.updateTime()}" update="currentTime"/> </h:form>
Create
ServerTimeBean.java
managed bean with theupdateTime()
method to set thecurrentTime
value as follows:@ManagedBean @RequestScoped public class ServerTimeBean { private String time; public void setTime(String time) { this.time = time; } public String getTime() { return time; } public void updateTime() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); this.time = sdf.format(new Date()); } }
We have used the <p:poll>
component to call listener method updateTime()
on ServerTimeBean
for every second by specifying interval="1"
, and updated the view to display current time using AJAX.
The poll component provides the following attributes, which provides additional control on its behavior:
AttributeName |
Description |
---|---|
|
JavaScript handler to execute before AJAX request begins. |
|
JavaScript handler to execute when AJAX request is completed. |
|
JavaScript handler to execute when AJAX request succeeds. |
|
JavaScript handler to execute when AJAX request fails. |
|
In autoStart mode, polling starts automatically on page load, to start polling on demand set it to false. |
|
Stops polling when true. |
Sometimes, we may want to have control on when to start/stop the polling process, stop polling based on some criteria, and so on. The PrimeFaces poll component provides these features with additional attributes giving you full control on polling process.
For example, we want to start polling when the Start button is clicked, and stop polling when the Stop button is clicked.
We will now demonstrate how to start and stop polling using external triggers such as start and stop buttons using following steps:
Create a form with a poll component and start/stop buttons to start and stop polling using following code:
<h:form> <p:outputLabel value="Current Time:" /> <p:outputLabel id="currentTime" value="#{serverTimeBean.time}"/> <p:poll interval="1" listener="#{serverTimeBean.updateTime()}" update="currentTime" widgetVar="currentTimePoller" autoStart="false"/> <br/> <p:button value="Start" onclick="currentTimePoller.start()" href="#" /> <p:button value="Stop" onclick="currentTimePoller.stop()" href="#"/><br/> </h:form>
We have set the autoStart
attribute to false, so that polling does not start automatically on page load. We have given a name for the poll component using widgetVar ="currentTimePoller"
so that we can invoke start()
and stop()
methods on the poll component. We have associated the start()
and stop()
methods to the button's onclick
events. So when we click on the Start button, polling will start and when we click on the Stop button, polling will be stopped.
Tip
PrimeFaces provides PrimeFaces push, which is better suitable for asynchronous processing. Prefer using PrimeFaces push over <p:poll>
component. For more information see http://www.primefaces.org/showcase/push/index.jsf.
RemoteCommand component provides an option to invoke server-side methods, say JSF managed bean methods, from JavaScript client-side code directly. This feature comes in handy when some task needs some client-side action and server-side logic. When you declare a RemoteCommand
component to invoke a JSF managed bean method, then you can call it like a JavaScript function, with the remoteCommand
name from the JavaScript code.
Suppose in our user
Registration Form, we want to validate e-mail format first on client side using Regex and if it is in valid e-mail format, then we want to check whether the e-mail is already in use or not using server-side logic. We can do this by using the RemoteCommand
component.
We will now take a look at how to invoke server-side logic from JavaScript code using RemoteCommand
. First we will check the e-mail format on client side using JavaScript, and then invoke server-side logic to check if the user provided e-mail already in use or not. Perform the following steps:
Create a method using following code in the
UserController
managed bean to check whether the given e-mail is already in use or not:@ManagedBean @RequestScoped public class UserController { public void checkEmailExists() { String email = this.registrationUser.getEmail(); if("admin@gmail.com".equals(email) || "test@gmail.com".equals(email)) { String msg = "Email ["+email+"] already in use."; FacesContext.getCurrentInstance().addMessage("registrationForm:email", new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg)); } } }
On the user registration page, create
validateEmail()
JavaScript function for checking e-mail format, and use aremoteCommand
component to invoke thecheckEmailExists()
actionListener
method to check whether the given e-mail is already in use or not:<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui"> <h:head> <title>Home</title> <script> function validateEmail() { var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/; var email = $.trim($(PrimeFaces.escapeClientId("registrationForm:email")).val()); if(email ==''){ $(PrimeFaces.escapeClientId("registrationForm:emailMsg")).text(""); $(PrimeFaces.escapeClientId("registrationForm:emailMsg")).attr("class", ""); return; } if( emailReg.test( email ) ) { checkDuplicateEmail(); } else { $(PrimeFaces.escapeClientId("registrationForm:emailMsg")).text("Invalid Email"); $(PrimeFaces.escapeClientId("registrationForm:emailMsg")).attr("class", "ui-message-error ui-widget ui-corner-all ui-message-error-detail"); } } </script> </h:head> <body> <h:form id="registrationForm"> <p:panel header="Registration Form" style="width: 800px;"> <h:panelGrid columns="3"> <p:outputLabel value="Email:"/> <p:inputText id="email" value="#{userController.registrationUser.email}" onblur="validateEmail();" /> <p:message id="emailMsg" for="email"/> <p:commandButton action="#{userController.register}" value="Register" update="registrationForm"/> </h:panelGrid> </p:panel> <p:remoteCommand name="checkDuplicateEmail" actionListener="#{userController.checkEmailExists()}" update="emailMsg"/> </h:form> </body> </html>
We have created a validateEmail()
JavaScript function to check the e-mail format using Regex and will be called on onblur
event on e-mail input element. In the validateEmail()
function, if the e-mail format is invalid we are showing the error message as "Invalid email!!", otherwise we are invoking the remoteCommand
checkDuplicateEmail
as JavaScript function, which invokes the UserController.checkemailExists()
method and add error message if the e-mail is already in use.
You have now been introduced to the PrimeFaces component library and did hands-on with some cool PrimeFaces features, but this is just the beginning. There are plenty more powerful yet easy to use Rich UI components, which we will be looking in further chapters. In this chapter, we took a glance at the PrimeFaces features and learned how to install and configure PrimeFaces. We have started by creating a simple HelloWorld application and learned performing validations and various AJAX features. We also learned how to use PrimeFaces PPR feature. Lastly, we have learned about polling and RemoteCommand components, which come very handy at times.
In the next chapter, we will take a look into the sample application TechBuzz that we will be building incrementally throughout the book. We will also discuss the application's domain model, creating the project structure and some sample screenshots of the application.