|
Articles Index
Contents
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="http://java.sun.com/jsf/extensions/dynafaces" %>
|
For JSP pages in the XML syntax, this looks like the
following:
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2" xmlns:jsfExt="http://java.sun.com/jsf/extensions/dynafaces" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
|
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="http://java.sun.com/jsf/html" xmlns:jsfExt="http://java.sun.com/jsf/extensions/dynafaces" xmlns:f="http://java.sun.com/jsf/core">
|
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:
- The
DynaFaces.fireAjaxTransaction function
executes, causing Dynamic Faces to initiate an Ajax request to the
server.
- The server returns a special XML response that the Dynamic
Faces
JavaScript library processes.
- 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:
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="http://java.sun.com/jsf/core"%> <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <%@taglib prefix="jsfExt" uri="http://java.sun.com/jsf/extensions/dynafaces"%> <%@taglib prefix="a" uri="http://java.sun.com/jmaki-jsf" %>
|
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
Ajax Developer
Resource Center
Ajax
Downloads
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.
|