Pump some AJAX into your JSF application

AJAX and JavaServer Faces: A perfect match for your client- and server-side elements

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.

Refactor the employee header/detail use-case

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:

  • Remove all MyFaces 1.1.1 jar files: myfaces-impl.jar, myfaces-ap.jar, tomahawk.jar, and sandbox.jar.
  • Go to the MyFaces Website, select the download page, and download myfaces-core-1.1.3-bin.zip and tomahawk-1.1.3-bin.zip to your local PC.
  • Extract all the jar files in the lib directory to your WEB-INF/lib directory. Of course, remove all the dependency common-.jar files and replace those with the ones in the MyFaces 1.1.3 version.
  • Modify the web.xml to update the MyFaces extension filter class reference to the following:

     <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.

Add/delete/validate employee functions

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";
     
   } 

Ajax4Jsf

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:

  • It's an open source solution for AJAX and specifically for JSF
  • It works with MyFaces components
  • No code rewrite or JavaScript is necessary for adding AJAX to an existing non-AJAX Web application
  • It has an active development and support community

To find out about more about the Ajax4jsf framework in detail, please see Resources.

Add Ajax4jsf to employee use-case

To add Ajax4jsf to our employee use-case, please follow these steps as described below:

  • Go to the Ajax4jsf Website and download the current version.
  • Modify the web.xml and add the following code:

       <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>  
    
  • Modify face-config.xml and add the following code:

     

    <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.

  • Add <%@ 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.

Conclusion

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.

Peter Wang is CIO of Google House, a consulting firm specializing in enterprise integration and IT outsourcing. Wang has been in the IT industry since 1994. He holds a master's degree in computer science and lives with his wife and two boys in Atlanta. He recently attended JBossWorld 2006 and was a break-out session speaker for VoIP application success using JBPM and JSF (see http://www.jbossworld.com/jbwv_2006/jems_verticles.htm).
1 2 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more