New Technologies for Ajax and Web Application Development: Project Dynamic Faces

   
By Jennifer Ball and Ed Burns, December 2006  

Articles Index

 

Contents
 
Setting up an Application to Use Dynamic Faces
Updating Areas of Your Page Using the ajaxZoneTag
Using the Dynamic Faces fireAjaxTransaction Method
Using Dynamic Faces With jMaki
Conclusion


 

Project Dynamic Faces is one of several projects that are extensions of JavaServer Faces technology. The previous article in this series introduced Project jMaki, which allows you to take any widget and wrap it in a JavaServer Pages tag handler or JavaServer Faces component. Project Dynamic Faces is another innovative project that provides a way to add Ajax functionality to a JavaServer Faces technology-based application. This project allows you to Ajax-enable any of the JavaServer Faces components that your web applications already use. You don't need to modify your components to give them the power of Ajax. Neither do you need to rewrite any of your application to add Ajax magic to it.

To add this Ajax magic to your application, you must first identify the parts of the pages in your application that you want the Ajax functionality to update. As developers of JavaServer Faces technology-based applications know, a JavaServer Faces page is represented by a tree of components. With Dynamic Faces, you can identify which components in the tree should benefit from asynchronous updates. Just as you use Ajax to update one part of the HTML DOM tree that represents the page, you use Dynamic Faces to update one part of the component tree that represents a JavaServer Faces page. Therefore, the Dynamic Faces paradigm is familiar to both Ajax developers and JavaServer Faces developers.

More importantly, Dynamic Faces leverages the JavaServer Faces component model to allow you to use Ajax capabilities in a more efficient way. Because of the collaborative nature of the component model, JavaScript technology events on some page components can cause asynchronous updates of any number of other components on the page. Dynamic Faces allows these asynchronous updates to occur as a result of only one Ajax request to the server rather than as a result of one Ajax request for each asynchronous update, thereby reducing the load on the server.

Dynamic Faces also leverages the JavaServer Faces component model to efficiently manage client-side and server-side state. When Dynamic Faces updates the state of the components on the client, it updates only the state that has changed -- and not the entire tree. The best part is that Dynamic Faces does all this behind the scenes, in a way that is completely consistent with the JavaServer Faces technology life cycle.

As well as making it easy to add Ajax functionality to an application, Dynamic Faces gives you flexibility with regard to how you add the Ajax capabilities. This article will discuss the following three ways to use Dynamic Faces to make your applications more interactive and dynamic:

  • Using the custom ajaxZone tag that Dynamic Faces provides to identify subtrees of the component tree that should be "Ajaxified"
  • Using the JavaScript library that Dynamic Faces provides to add Ajax functionality to individual components
  • Adding an Ajax-enabled component, such as a jMaki widget, to a page

Before you read a description of these techniques, let's find out what it takes to configure your application to use Dynamic Faces.

Setting up an Application to Use Dynamic Faces

Dynamic Faces takes advantage of the runtime extensibility of JavaServer Faces technology by adding Ajax capabilities to a standard JavaServer Faces 1.2 technology implementation. At the heart of Dynamic Faces are the custom Lifecycle and ViewRoot implementations. These two implementations are extensions of the standard Lifecycle and ViewRoot implementations that JavaServer Faces technology supplies. A standard Lifecycle object represents an instance of the JavaServer Faces life cycle, and a standard ViewRoot object represents the root of a component tree. Together, the custom Lifecycle object and custom ViewRoot object enable the JavaServer Faces life cycle to handle Ajax transactions and re-render portions of a component tree without requiring a full-page refresh. These custom implementations defer to the standard implementations for non-Ajax requests.

To make the JavaServer Faces technology runtime aware of the custom Lifecycle object, you must tell the FacesServlet instance about the object using an initialization parameter in your deployment descriptor:

<servlet>
                    

    <servlet-name>Faces Servlet</servlet-name>
                    

    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
                    

    <init-param>
                    

        <param-name>javax.faces.LIFECYCLE_ID</param-name>
                    

        <param-value>com.sun.faces.lifecycle.PARTIAL</param-name>
                    

    </init-param>
                    

    <load-on-startup>1</load-on-startup>
                    

</servlet>
                    

                  
 

Also, you must add the Java Archive (JAR) files on which Dynamic Faces depends to the lib directory of the application's web archive (WAR) file. Because Dynamic Faces is based on the Java Platform, Enterprise Edition 5 (Java EE 5), all but one of the dependencies you need are already available. This last dependency is Shale Remoting, which Dynamic Faces uses to load JavaScript technology files and other resources from the Java classpath. Shale Remoting, in turn, depends on commons-logging, and therefore you must make commons-logging available to the application.

Finally, you must declare the Dynamic Faces tag library in each page that uses it. For JavaServer Pages (JSP) technology pages in the standard non-XML syntax, this declaration looks like the following: 

<%@ taglib prefix="jsfExt"
                    

 uri="#" %>
                  
 

For JSP pages in the XML syntax, this looks like the following:

<jsp:root xmlns:jsp="#" version="1.2"
                    

      xmlns:jsfExt="#"
                    

      xmlns:h="#"
                    

      xmlns:f="#">
                    

                  
 

If you are using Facelets instead of JSP technology, the syntax is very similar to the JSP XML syntax, as shown here:

<html xmlns="http://www.w3.org/1999/xhtml"
                    

      xmlns:h="#"
                    

      xmlns:jsfExt="#"
                    

      xmlns:f="#">
                    

                  
 

Finally, you need to add the <jsfExt:scripts /> tag to your page:

<f:view>

<html>
 <head>
    ...
     
                     <jsfExt:scripts />
 </head>
 <body>
    ...
                  
 

This tag renders <script> elements for the JavaScript technology files that Dynamic Faces requires.

That's it. Now, you are ready to start using Dynamic Faces to add Ajax functionality to your application.

As an alternative to manually configuring your application, you can use the Dynamic Faces download bundle, which includes blank applications for both JSP and Facelets view description technologies. If you start with the blank application, all the setup work has been done for you, and you can just start writing pages.

Updating Areas of Your Page Using the ajaxZoneTag

One way to identify which components on the page to Ajax-enable is to wrap them with the ajaxZone custom tag that Dynamic Faces provides. When you do this, you are telling Dynamic Faces to asynchronously update only that part of the component tree that you have identified with the ajaxZone tag.

For example, suppose you have a page with a set of buttons that a customer can use to select either a standard or deluxe package option when buying a car online. When the customer clicks one of the buttons, the values in a set of other components change without causing a full-page refresh. Also, when the customer changes the values in one of the other components, the price displayed for the car also displays without a full-page refresh.

Figure 1 shows a screen capture of the page from the cardemo application, which allows you to choose package options for a car.

Figure 1: Choosing Package Options for a Car
 

Figure 1 shows two zones that are demarcated by ajaxZone tags. When the customer clicks one of the buttons in zone 2, the values of the components in that zone also change. When the customer changes the values of one of the components in zone 2, the Your Price output component in zone 1 changes.

To accomplish this, you wrap the entire set of components in ajaxZone tags, as shown in the following markup:

<jsfExt:ajaxZone id="zone1">
                    

     <h:panelGrid columns="2">
                    

     <h:outputText styleClass="subtitle"
                    

              value="#{bundle.basePriceLabel}"/>
                    

       <h:outputText
                    

                binding="#{carstore.currentModel.components.basePrice}"/>
                    

        <h:outputText styleClass="subtitle"
                    

                value="#{bundle.yourPriceLabel}"/>
                    

        <h:outputText value="#{carstore.currentModel.currentPrice}"/>
                    

     </h:panelGrid>
                    

</jsfExt:ajaxZone>
                    

                     

<jsfExt:ajaxZone id="zone2"
                    

  action="#{carstore.currentModel.updatePricing}">
                    

     <h:commandButton id="Standard" value="#{bundle.Standard}"
                    

    styleClass="#{carstore.customizers.Standard.buttonStyle}"
                    

   actionListener="#{carstore.choosePackage}"/>
                    

     <h:commandButton id="Deluxe" value="#{bundle.Deluxe}"
                    

    styleClass="#{carstore.customizers.Deluxe.buttonStyle}"
                    

     actionListener="#{carstore.choosePackage}"/>
                    

     <h:outputText value="#{bundle.Engine}"
                    

   styleClass="optionLabel"/>
                    

     <h:selectOneMenu styleClass="optionValue"
                    

  binding="#{carstore.currentModel.components.engine}"/>
                    

     <h:outputText value="#{bundle.Speakers}"
                    

       styleClass="optionLabel"/>
                    

     <h:selectOneRadio styleClass="optionValue"
                    

 binding="#{carstore.currentModel.components.speaker}"/>
                    

</jsfExt:ajaxZone>
                  
 

The preceding markup includes two zones named zone1 and zone2. As the markup shows, zone 1 contains only output components, so it does not produce any Ajax requests. Zone 2 contains both input and output components. Therefore, the components in zone2 initiate an Ajax request when the customer clicks either of the two buttons or selects any of the options in the menu or radio button list. This request will cause the action referenced by the method expression #{carstore.currentModel.updatePricing} to be invoked.

When you use zones, each Ajax transaction will cause all of the zones in the page to update. The net effect of the preceding example is that the Ajax functionality automatically updates the car-pricing data in zone 1 when the user selects any of the input components in zone 2.

Note that you do not have to write a single line of JavaScript technology code to implement this example, nor do you need any custom components. This application uses plain and simple JavaServer Faces components as you've always known them, but they are now Ajax-enabled.

The ajaxZone tag gives the page author a simple, familiar, and intuitive way to leverage the power of Dynamic Faces. In most simple cases, the ajaxZone tag gives page authors what they need. The ajaxZone tag supports many other attributes that allow you to further customize its operation. See the documentation for the ajaxZone tag for a complete list of attributes.

The next section talks about another way to use Dynamic Faces when you want finer-grained control over how the components in your pages are Ajax-enabled.

Using the Dynamic Faces fireAjaxTransaction Method

To execute more precise control over Ajax-related tasks, you can work with the built-in JavaScript technology library that Dynamic Faces provides. By using the DynaFaces.fireAjaxTransaction JavaScript function right from your existing component tags,  you can have more fine-grained component-level control over how groups of components in a page are asynchronously updated.

For example, suppose that you want some of the components in the page to respond to one kind of JavaScript event, such as onclick, but you want other components in the page to respond to other kinds of JavaScript events. Also, suppose that you want each component that generates an Ajax request to cause a different area of the component tree to be asynchronously updated. To accomplish these tasks, you use the fireAjaxTransaction function.

To use the fireAjaxTransaction function, do the following:

  • Add a JavaScript event attribute, such as onclick, to a component tag.
  • Set the value of the attribute to the DynaFaces.fireAjaxTransaction function.
  • Pass a set of parameters to the function.

The following markup represents part of a page from a simple Hello World example, in which a user can enter his or her name and click a button so that the application responds with a greeting that includes the user's name.

...
                    

<f:view>
                    

...
                    

<h:form id="form" prependId="false">
                    

...
                    

<h:graphicImage value="wave.med.gif"/>
                    

<p>
                    

Hello, my name is Duke.  What is your name?
                    

<p>
                    

<h:inputText id="input" value="#{testBean.name}"/>
                    

<h:commandButton id="button"
                    

              actionListener="#{testBean.changeText}"
                    

           onclick="DynaFaces.fireAjaxTransaction(this,
                    

         {execute: 'input', 'button',
                    

                 render: 'input', 'text'});  return false;"           
                    

            value="click"/>
                    

<p>
                    

<h:outputText id="text" value="#{testBean.text}"/>
                    

</h:form>
                    

...
                    

</f:view>
                  
 

In the preceding example, the inputText tag represents an input field. When the user enters something in the input field and clicks the button represented by the commandButton tag, the following happens:

  1. The DynaFaces.fireAjaxTransaction function executes, causing Dynamic Faces to initiate an Ajax request to the server.
  2. The server returns a special XML response that the Dynamic Faces JavaScript library processes.
  3. The appropriate library functions update the HTML DOM tree with the newly rendered values.

To tell the fireAjaxTransaction function how to produce the Ajax request, you pass a set of parameters to it. In the case of the preceding example, you pass two parameters to the fireAjaxTransaction function.  Here again is the call to the fireAjaxTransaction function:

   onclick="DynaFaces.fireAjaxTransaction(this,
                    

               {execute: 'input', 'button',
                    

                 render: 'input', 'text'});  return false;"
                  
 

The this parameter refers to the tag representing the button that fired the event. The other parameters consist of options that direct Dynamic Faces on how to process the request. In this case, the options are execute and render.

The execute and render options refer to portions of the JavaServer Faces technology life cycle, as shown in Figure 2.

Figure 2: How Dynamic Faces Demarcates the JavaServer Faces Technology Life Cycle Using the execute and render Options
 

The execute portion is the part of the life cycle that is executed during a postback. It includes the phases that handle data conversion, validation, and updating of the model object.  The render portion, as its name suggests, renders the page as a result of a request for the page. For more information on the JavaServer Faces life cycle, please see " The Life Cycle of a JavaServer Faces Page" in Chapter 9 of the Java EE 5 Tutorial.

The execute option used with the call to the fireAjaxTransaction function lists the IDs of those components that must be traversed during the execute portion of the JavaServer Faces life cycle, as shown in this line from the Hello World example:

execute: 'input', 'button'
 

The input component that accepts the user's name must go through the execute portion of the life cycle because its data must be saved to the model object. The button component should also go through the execute portion of the life cycle because the Invoke Application phase, which handles events such as those fired by the button, is part of the execute portion of the life cycle.

When the render portion of the life cycle is rendering a page that uses Dynamic Faces, it renders only selected components on the page as a result of an Ajax request. You use the render option to list the IDs of the components that you want to be re-rendered, as shown in this render option from the Hello World example:

render: 'input', 'text'
 

In this case, the render portion of the life cycle re-renders the input and text components on the page as a result of the Ajax request. When the user clicks the button, the input field, representing the input component, and the output text, representing the text component, are rendered again. The input field is re-rendered to clear the value that the user had entered before clicking the button. The output text is re-rendered to display a message that includes the value the user entered into the input field before clicking the button. The other components on the page do not need to be re-rendered.

In addition to the execute and render options, you can use other options to further customize how Dynamic Faces handles the event. See this reference page of JavaServer Faces technology extensions to use with Ajax for a list of all the optional arguments to the fireAjaxTransaction function. The important lesson to remember is that using the fireAjaxTransaction function gives you more control over what components in your page benefit from Ajax. In fact, the fireAjaxTransaction function allows you to Ajax-enable any component in your page without requiring you to provide any JavaScript technology or other code.

Using Dynamic Faces With jMaki

So far, you have seen how you can use Dynamic Faces to re-render existing JavaServer Faces components with Ajax. But what if you want to add one of the cool Ajax-enabled widgets that you've seen to a JavaServer Faces technology-based application?

You can leverage Project jMaki to wrap your favorite widget in a JavaServer Faces component. This way, you get all the benefits of the JavaServer Faces component model, and you get the flexibility of using any widget wrapped as a JavaServer Faces component. At the same time, you avoid having to write both the extra JavaScript technology code to implement the Ajax functionality for existing components and the Java platform code normally required to create a JavaServer Faces component for your widget. See the previous article in this series for an overview of Project jMaki.

So what does it take to use jMaki with Dynamic Faces? For page authors, it's as easy as dropping the tag associated with the jMaki widget into the page, as the previous article in this series described.

To get a jMaki widget to work with Dynamic Faces, the widget developer makes some small modifications to a jMaki widget's component.js file. The changes allow the jMaki widget to take full advantage of the sophisticated component state-management system that JavaServer Faces technology offers and to get it to properly transfer the headers that Dynamic Faces requires. The details of these modifications are beyond the scope of this article, but you can read about them in this blog by Ed Burns, the co-lead of the JavaServer Faces technology specification.

The Dynamic Faces development team has already done the work of converting three of the jMaki widgets to work with Dynamic Faces. The converted jMaki-wrapped widgets are the script.aculo.us in-place editor widget, the Dojo fisheye widget, and the Dojo inline-editor widget. You can see these jMaki widgets in action in Dynamic Faces applications in the Project Dynamic Faces and jMaki page.

While converting the fisheye widget, the development team also modified the jMaki APIs so that a widget can fire a JavaServer Faces technology value-change event, as shown by the following tag, which represents a jMaki fisheye widget wrapped as a JavaServer Faces component:

<a:ajax name="dojo.fisheye"
                    

     value="#{fishEyeBean.selectedIndex}"
                    

     valueChangeListener="#{fishEyeBean.valueChanged}"
                    

  args="{items:[
                    

         {iconSrc:'images/150x126_jalopy.jpg',caption:'Jalopy',index:0},
                    

     {iconSrc:'images/150x126_luxury.jpg',caption:'Luxury',index:1},
                    

     {iconSrc:'images/150x126_roadster.jpg',caption:'Roadster',index:2},
                    

         {iconSrc:'images/150x126_suv.jpg',caption:'SUV',index:3}
                    

 ]}"
                    

/>
                    

                  
 

Check out the demo Using Dynamic Faces with jMaki to see a running example of the fisheye widget in a Dynamic Faces application.

The Dynamic Faces and jMaki development teams are working to make sure that all jMaki widgets support Dynamic Faces. If you are interested in contributing to this effort, see the Project jMaki community page.

For now, let's take the page author's view. To see how to use the jMaki script.aculo.us in-place editor widget with Dynamic Faces, let's include the widget in a JavaServer Faces data table component so that you can edit the value of a cell in the table.

In the JSP technology page, you must declare the required tag libraries and the extra Dynamic Faces and jMaki tags, as shown here:

<%@taglib prefix="f"
                    

       uri="#"%>
                    

<%@taglib prefix="h"
                    

 uri="#"%>
                    

<%@taglib prefix="jsfExt"
                    

   uri="#"%>
                    

<%@taglib prefix="a"
                    

 uri="#" %>
                    

                  
 

Finally, you add the widget to the page by including a jMaki ajax tag that specifies the in-place editor wrapped as a jMaki widget:

<h:form>
                    

                     

  <h:dataTable
                    

              ...
                    

         rows="10" binding="#{ResultSetBean.data}"
                    

               value="#{ResultSetBean.list}"
                    

               var="customer">
                    

    <h:column>
                    

      <f:facet name="header">
                    

        <h:outputText  value="Account Id"/>
                    

      </f:facet>
                    

      <h:outputText id="accountId"
                    

                     value="#{customer.accountId}"/>
                    

    </h:column>
                    

                     

    <h:column>
                    

      <f:facet name="header">
                    

        <h:outputText  value="Customer Name"/>
                    

      </f:facet>
                    

          
                     <a:ajax name="scriptaculous.inplace"                       
value="#{customer.name}"/>
</h:column> </h:dataTable> ... </h:form> </body> </html> </f:view>
 

Figure 3 shows what the preceding page looks like when it is rendered.


Figure 3: Before the User Changes the Value of a Cell
 

Figure 4 shows what happens when the user clicks one of the links in the Customer Name column's cells.


Figure 4: After the User Clicks a Link in the Customer Name Column
 

Notice that when the user clicks on a link in the Customer Name column, the customer name link is replaced with an input component, a button, and a Cancel link so that the user can edit the customer name in place. If the user clicks Cancel instead of the button, the cell is re-rendered with the original value. If the user enters a value and clicks the button, the new value is sent to the server using Ajax so that the model is updated with the new value.  Then, the edited cell is re-rendered.  Figure 5 shows the same page with the re-rendered cell.


Figure 5: After the User Submits the New Value to the Server and the Page Is Re-rendered With the New Value
 

To see this component in action, take a look at the scroller component demo.  This particular demo shows a multi-page, scrollable demo.  This section does not describe how to implement the scrolling feature of the demo; it only describes how to use the jMaki script.aculo.us in-place editor widget in a single-page table.

Conclusion

Project Dynamic Faces gives you a flexible, efficient way to add Ajax capabilities to your JavaServer Faces technology-based application without requiring you to give up any of the benefits provided by the JavaServer Faces component model. With the help of the built-in JavaScript library, the Ajax implementation, and the interaction with the component model that Dynamic Faces provides, you'll find it's also easier to add Ajax functionality using Dynamic Faces. Even better, your JavaServer Faces technology-based applications can benefit from the extra flexibility that jMaki widgets provide.

For More Information

New Technologies for Ajax and Web Application Development: Project jMaki, Project Dynamic Faces, and Project Phobos (Part 1)
New Technologies for Ajax and Web Application Development: Project jMaki (Part 2)
Dynamic Faces
JavaServer Faces Technology
JavaServer Pages (JSP) Technology
Project jMaki
JavaScript Technology
Dojo Toolkit
Script.aculo.us

About the Authors

Jennifer Ball is a staff writer at Sun Microsystems. She writes about web application technologies that are part of the Java EE platform.

Ed Burns is a senior staff engineer at Sun. He has worked on a wide variety of client and server side web technologies since 1994, including NCSA Mosaic, Mozilla, the Sun Java Plug-in, Jakarta Tomcat, and JavaServer Faces technology. Read his blog.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.