Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
In my previous article, "Put on a Happy MyFace" (July 2006), I showed how to use the JavaServer Faces (JSF) MyFaces component-based framework to create an employee header/detail use-case. Other functionality needs to be added to this application, such as the ability to add or delete an employee. In this article, I not only introduce these new functions, but also demonstrate how to use AJAX (Asynchronous JavaScript and XML) to improve the JSF Web application user experience. AJAX is an old technology with a new life. One of the biggest advantages of AJAX is that it improves the user's experience. In traditional Web applications, the entire Web content is rendered for every HTTP request every time. With AJAX, only a portion of content is rendered. Put simply, users can have a similar or the same experience working with a Web application as they have when working with a Windows-based application. JSF and AJAX are a perfect match when it comes to building a so-called RIA (rich Internet application). You want to know how? Just follow me.
Before I begin adding the new functions, I want to show you how to upgrade MyFaces from version 1.1.1 to the latest version, 1.1.3, which features many improvements and bugs fixes. One benefit for us using 1.1.3 in this use-case is that the version 1.1.3 tab panel has improved the tab's look and feel. It also provides a stable foundation for me to use AJAX, which I will detail in a subsequent section. To upgrade MyFaces 1.1.1 to 1.1.3, please follow the steps below:
<filter-name>extensionsFilter</filter-name>
<filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
In addition to the MyFaces version upgrade, I also changed the employee use-case package name to better present the data model classes and JSF managed beans.
Now that I have refactored the code and upgraded MyFaces, I am ready to add the two new functions. As shown in Figures 1 and 2, I want to create an Add button at the bottom of the Employee Information screen and add a delete function, represented by a trash can icon, to the list of employees.
Figure 1. Add employee to list. Click on thumbnail to view full-sized image.
Figure 2. Delete employee from list. Click on thumbnail to view full-sized image.
When users click on the Add button, the information entered in the employee detail section will be added to the list (see Figure 3).
To add this functionality, in the employee.jsp, I use the <t:commandButton> MyFaces component and associate the action with employeeTable.addEmployee; see Listing 1:
Listing 1
<t:commandButton action="#{employeeTable.addEmployee}" value="Add"
alt="Add New Employee Information"/>
In the employeeTable.addEmployee method shown in Listing 2, I first check if the employee record entered here is valid. If it is, the new record is added
to the list, and the proper message displays on the screen, as illustrated in Figure 3.
Listing 2
public String addEmployee()
{
// Get rows and update them in the database
if (employee!=null && !employee.isValid())
{
handleValidationException(employee);
}
else
{
Employee newEmployee = new Employee();
copyProperties(newEmployee,getEmployee());
employees.add(newEmployee);
addMessage("Employee " +employee.getName() + " information has been added successfully.");
}
return "OK";
}
Figure 3. Add an employee with confirmation message. Click on thumbnail to view full-sized image.
When a user clicks on the Delete icon in the list, that selected employee row will be deleted; see Figure 4.
Figure 4. Delete an employee with confirmation message. Click on thumbnail to view full-sized image.
To add this deletion functionality, I use the MyFaces <t:commandLink> component, with trash can image, as shown in Listing 3:
Listing 3
<t:commandLink action="#{employeeTable.removeEmployee}" >
<t:graphicImage value="/resources/images/icons/delete.gif" border="0" alt="Click here to remove the record" />
<f:param name="selectedRowIndex" value="#{rowIndex}"/>
</t:commandLink>
In employeeTable.removeEmployee, the employee record is removed from the list; see Listing 4:
Listing 4
public String removeEmployee()
{
final int selectedRowIndex = Integer.parseInt
((String)getParameter("selectedRowIndex"));
Employee employee = (Employee) employees.get(selectedRowIndex);
employees.remove(selectedRowIndex);
if (!employees.isEmpty())
{
// Set the selected employee to the first one
setSelectedRowIndex(Math.min(0,employees.size()-1));
setEmployee((Employee)employees.get(this.getSelectedRowIndex()));
}
else // If already empty
{
setSelectedRowIndex(-1);
setEmployee(new Employee());
}
setShowDetailView(true);
addMessage("Employee " +employee.getName() + " information has been removed successfully.");
return "OK";
}
You have seen how the add/delete functions work, but what about validation? Should we use JavaScript or a JSF build-in for validation, or some kind of hybrid approach? The answer is AJAX. The key point of AJAX is that it's an asynchronous HTTP request and a partial rendering. In other words, users never see the whole page refresh or reload. In the validation function use-case, the JSF managed bean will handle the validation action and rules on the server side; AJAX will help with the on-demand asynchronous request and partial rendering of the validation message when a validation error occurs.
Among all the AJAX solutions for JSF, I chose the open source Ajax4jsf. Here are some benefits of using Ajax4jsf verses other solutions:
To find out about more about the Ajax4jsf framework in detail, please see Resources.
To add Ajax4jsf to our employee use-case, please follow these steps as described below:
<context-param>
<param-name>org.ajax4jsf.SKIN</param-name>
<param-value>DEFAULT</param-value>
</context-param>
<filter>
<display-name>Ajax4jsf Filter</display-name>
<filter-name>ajax4jsf</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>ajax4jsf</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<render-kit>
<renderer>
<component-family>javax.faces.Command</component-family>
<renderer-type>javax.faces.Button</renderer-type>
<renderer-class>org.apache.myfaces.renderkit.html.jsf.ExtendedHtmlButtonRenderer</renderer-class>
</renderer>
<renderer>
<component-family>javax.faces.Command</component-family>
<renderer-type>javax.faces.Link</renderer-type>
<renderer-class>org.apache.myfaces.renderkit.html.jsf.ExtendedHtmlLinkRenderer</renderer-class>
</renderer>
</render-kit>
You may skip this step for the current final release of the 1.0 version.
<%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j" %> in all JavaServer Pages (JSP) pages that reference Ajax4jsf components.
To add AJAX to the use-case, use <a4j:support> to handle AJAX field-level validation. In employeeHeader.jsp, add <a4j:support> for first name and last name input fields:
Listing 6
<t:inputText value="#{employee.firstName}" id="firstName" >
<a4j:support actionListener="#{employeeTable.processEmployeeRowValidation}"
event="onblur" reRender="eheader,msg">
</a4j:support>
</t:inputText>
<f:verbatim> </f:verbatim>
<t:inputText value="#{employee.lastName}" id="lastName">
<a4j:support actionListener="#{employeeTable.
processEmployeeRowValidation}" event="onblur" reRender=
"eheader,msg"></a4j:support>
</t:inputText>
I add the same <a4j:support> in employeeInfo.jsp as well:
Listing 7
<t:graphicImage value="/resources/images/icons/alert.gif"
alt="Invalid Record" rendered="#{!employeeTable.employee.valid}"
id="invalidicon"></t:graphicImage>
<t:inputText value="#{employeeTable.employee.firstName}" id="firstName" >
<a4j:support actionListener="#{employeeTable.processEmployeeInfoValidation}"
event="onblur" reRender="detailtab,msg">
</a4j:support>
</t:inputText>
<f:verbatim> </f:verbatim>
<t:inputText value="#{employeeTable.employee.lastName}" id="lastName">
<a4j:support actionListener="#{employeeTable.processEmployeeInfoValidation}"
event="onblur" reRender="detailtab,msg">
</a4j:support>
</t:inputText>
In both cases above, an AJAX request is fired on a blur event of input fields of both last name and first name. The corresponding
processEmployeeRowValidation or processEmployeeInfoValidation method is called to handle the validation rules and actions. In this use-case, values of first name and last name cannot
be empty. When the validation rules fire, the proper validation error message displays on the screen (see Figures 5 and 6).
To add this functionality, I just simply add the <a4j:outputPanel> around the <t:messages> components:
<a4j:outputPanel id="msg">
<t:messages errorClass="error"/>
</a4j:outputPanel>
Figure 5. Validation message when changing employee record in the list. Click on thumbnail to view full-sized image.
Figure 6. Validation message when changing employee record in the detail page. Click on thumbnail to view full-sized image.
In addition to the AJAX validation, I also change <t:commandLink> and <t:commandButton> to <a4j:commandLink> and <a4j:commandButton> in both employee.jsp and employeeHeader.jsp to take advantage of the AJAX partial rendering. Thus, only the employee list and employee detail section is refreshed for
each action.
To experience the AJAX effect and see AJAX in action, just follow the steps on how to run the use-case in my previous article.
With just a few Ajax4jsf components and a slight modification, I have turned an existing MyFaces Web application into an AJAX Web application, or a so-called RIA (rich Internet application). Not only does Ajax4jsf demonstrate the power of AJAX in JSF, but it also shows how flexible and extensible the JSF framework is.
In "Put on a Happy MyFace," I showed you how to use JSF and MyFaces components to create a JSF Web application. In this article, I added the add/delete/update/validation functions to that application along with AJAX capability. Now you should have a good understanding of what JSF and AJAX can do to help you to build a real-world Web application. There are other interesting components in both JSF and Ajax4jsf, which you can explore and hopefully make good use of.
Read more about Tools & Methods in JavaWorld's Tools & Methods section.
Archived Discussions (Read only)