Project Dynamic Faces
This chapter describes how to use Project Dynamic Faces to add Ajax capabilities to JavaServer Faces components.
Introduction to Project Dynamic Faces
Project Dynamic Faces allows you to add Ajax functionality to any of the JavaServer Faces UI components that you already use. You don't need to modify components or rewrite any of your application code to give your applications the benefits of Ajax. Neither do you need to write extra JavaScript code in most cases, because Dynamic Faces provides its own set of JavaScript libraries that implement the Ajax functionality for you. At the same time, Dynamic Faces ensures that the powerful component model and specialized life cycle that are unique to JavaServer Faces technology continue to work as expected.
Understanding How Dynamic Faces Works
As Chapter 2, Dynamic User Interfaces describes, the purpose of Ajax is to allow you to asynchronously update only part of a page in response to user-initiated events rather than expect the user to wait for a full-page refresh. The way Dynamic Faces achieves this while allowing you to take advantage of the JavaServer Faces component model and life cycle is by providing the following features:
A custom JSP tag, called ajaxZone, which you use to identify the parts of the component tree that you want the Ajax functionality to update.
A set of JavaScript functions that apply the Ajax functionality to the components you identify, send Ajax requests to the server, and update the DOM tree on the client with the Ajax response from the server. You can also use some of these functions directly on the components for finer-grained control over how individual components experience asynchronous updates.
A set of APIs that define the server-side objects that process the Ajax request, traverse the sub-trees of components that need to be asynchronously updated during the proper phases of the life cycle, and construct and return Ajax responses to the client.
The more commonly used JavaScript functions supplied by Dynamic Faces include:
fireAjaxTransaction: When invoked, this function initiates an Ajax request with a set of options indicating which components should experience asynchronous updates.
installDeferredAjaxTransaction: Installs a fireAjaxTransaction function onto a DOM element. The invocation of the fireAjaxTransaction is deferred, meaning that it is invoked only when a certain user-initiated event occurs.
inspectElement: Goes through elements demarcated by an ajaxZone tag and identifies which ones should exhibit Ajax behavior. By default, it will add Ajax behavior to input and option elements.
The most important server-side objects that take part in handling an Ajax request and constructing and serving an Ajax response include:
PartialTraversalViewRoot: A custom ViewRoot implementation that represents one part of a component tree that needs to be asynchronously processed or rendered.
PartialTraversalLifecycle: A custom Lifecycle implementation that assists the custom ViewRoot implementation to render the appropriate sub-trees of components at the correct time.
AsyncResponse: Handles the formatted XML response that represents the partial update of the component tree.
The following example shows a simple use case of the ajaxZone tag on a JSP page:
... <jsfExt:ajaxZone id="zone1" execute="zone1" render="zone2"> <h:selectOneMenu id="country" value="#{ApplicationBean.country}" valueChangeListener="#{ApplicationBean.updateCapital}"> <f:selectItems value="#{ApplicationBean.countries}"/> </h:selectOneMenu> </jsfExt:ajaxZone> <jsfExt:ajaxZone id="zone2"> <h:outputText id="capital" value="#{ApplicationBean.stateCapital}"/> </jsfExt:ajaxZone> ...
The page contains two zones demarcated by ajaxZone tags. These zones are identified as zone1 and zone2. The first zone includes a selectOneMenu component with the ID country. The other zone includes an output component with the ID capital. Assuming you have a managed bean called ApplicationBean that defines the required properties and handler method, this example allows a user to select a country from the country component and see the capital of that country asynchronously render in the capital output component on the page.
Notice that zone1 includes execute and render attributes. These attributes refer to groups of phases in the life cycle, as shown by the following figure:
Figure 4-1 The JavaServer Faces Life Cycle
The execute part of the life cycle 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 attribute of the zone1 tag is set to zone1, which means that the components in this zone must be traversed during the execute portion of the JavaServer Faces life cycle. The country menu component, which is included in zone1, must go through the execute phases because it has a value-change event registered on it, and the handler for this event needs to update the model value of the capital output component. Therefore, it needs to go through the Update Model Values phase of the life cycle.
The render attribute of the zone1 tag is set to zone2, which means that the components in zone2 must be re-rendered after the components in the zone1 tag have executed. This is so the capital component displays the new capital value when the page is re-rendered.
The following figure illustrates how this page is processed:
Figure 4-2 Flow of an Ajax Request and Response
The following steps outline what's happening in this figure and explain how the JavaScript functions and APIs play a part in “Ajaxifying” the components:
The client makes an initial request for the page. When the client makes an initial request for the page, the server renders the entire page, including any necessary Dynamic Faces JavaScript code, to the client. The component tree is now represented as a DOM tree in the browser. The ajaxZone tag automatically inserts into the page some JavaScript that inspects the DOM elements contained within the zone so that they will fire Ajax requests when activated.
The user selects a country from the menu. When the user selects a country from the menu, the fireAjaxTransaction function attached to the menu component is invoked. The JavaScript code inserted into the page in step 1 now ensures that the Ajax request is sent to the server in such a way that the life cycle can properly perform its tasks. These tasks include restoring the state of the current view and updating the country component's value with the request data.
The life cycle traverses the view. On the server, the PartialViewRoot instance is at the root of the partial tree of components sent with the Ajax request. In this case, the tree contains the country component. Together, the PartialViewRoot and PartialTraversalLifecycle objects guide the country component through the execute phases of the life cycle so that its handler method can update the model value of the capital component.
The server returns an Ajax response. Using the AsyncResponse instance, the PartialViewRoot constructs an Ajax response, which consists of some XML that contains the new value of the capital component, and sends the response to the client.
The HTML DOM tree is updated with the Ajax response. The JavaScript functions replace the DOM element representing the capital in the DOM tree with the data from the Ajax response.