Asynchronous JavaScript and XML (Ajax) is a technique for making the user interfaces of web applications more responsive and interactive. Because of its flexible and pluggable UI component model, JavaServer Faces technology is the perfect framework to use when adding Ajax functionality to your applications. With the DOJO JavaScript toolkit, it's even easier for component developers to add this functionality. This tutorial describes how to add the power of Ajax to JavaServer Faces components with some help from the DOJO toolkit. Contents
What is Ajax?If you've surfed the web at all lately, most likely you've seen Ajax in action without realizing it. Ajax can help increase the speed and usability of an application's web pages by updating only part of the page at a time, rather than requiring the entire page to be reloaded after a user-initiated change. Through the power of Ajax, the pages of your application can exchange small amounts of data with the server without going through a form submit. The Ajax technique accomplishes this by using the following technologies:
![]() Figure 1: General Sequence of Ajax Request Figure 1 illustrates the following steps in a generalized Ajax request:
JavaServer Faces Technology and AjaxJavaServer Faces technology is designed to make web application development easier for page authors and developers alike. The most important feature that JavaServer Faces technology offers is its flexible and extensible component model that allows component developers to easily create their own pluggable components. At the same time, a page author can include a set of components on any of their pages using a component tag library without having to know the details of how a component works. What's more is that the modularity of the components makes them more toolable. This means a page author can just drag and drop the components onto a page using a tool such as Sun Java Studio Creator or the NetBeans IDE. These characteristics make JavaServer Faces technology the perfect companion to Ajax functionality. Instead of requiring page authors to include JavaScript code on the page itself, component developers can encapsulate it inside the component. In this way, page authors can make use of all of the Ajax capabilities, while at the same time the complexity of the components' JavaScript is hidden from them. In addition, developers can expose the JavaScript in these JavaServer Faces-developed Ajax-capable components to enable even more powerful interactions. Furthermore, because the Ajax functionality is encapsulated in the component rather than embedded in the page, the Ajax functionality is more portable and page authors have an easier time maintaining their pages. The DOJO Toolkit and AjaxEven with the help of JavaServer Faces technology, adding Ajax support still requires writing some JavaScript, even though it is hidden from the page author. Although JavaServer Faces technology does help overcome some of the shortcomings associated with using Ajax, it cannot solve all of the problems, such as inconsistent browser support. As a result of the problems associated with Ajax, new Ajax frameworks have emerged to overcome them. Once you learn to master one of these frameworks, you'll find it helps a lot with developing Ajax-aware applications and resolving incompatibility issues and the other common Ajax pitfalls. One of the frameworks that makes it easier to use Ajax is the DOJO open-source JavaScript toolkit. First of all, it frees developers from writing more common JavaScript functions by providing pluggable JavaScript libraries geared toward particular tasks, such as event-handling. It also overcomes some of the inconsistent browser support of Ajax as well as the memory leaks that plague JavaScript. Perhaps most importantly to the Ajax developer, it supports the XMLHttpRequest mechanism so that
you don't need to deal with it yourself in your JavaScript.In this tutorial, you'll see how to use DOJO and JavaServer Faces technology to include Ajax functionality in a custom component. Using an Ajax-aware Custom ComponentIf you are a page author and you just want to use an Ajax-aware component, you'll be pleased to know that it is as easy as using any other JavaServer Faces component: 1. Include a reference to the component's tag library along with the standard JavaServer Faces tag libraries:
2. Use the tag in the page:
The rest of what you need, such as the component, renderer, and tag handler classes, as well as the files containing the JavaScript should be packaged by the application developer. Check out the list of Ajax-aware components offered by the Java Blueprints Solutions Catalog. There, you'll find instructions on how to use each component and a screen shot and demo of each component. See How to Use the Dynamic Text Component for instructions on how to use the component discussed in this tutorial. Steps to Include Ajax Support in A Custom ComponentAdding any kind of Ajax support to a custom component involves a few basic steps. More complex Ajax support might require additional steps. The rest of this tutorial assumes that you know the steps for creating a custom component. If not, please refer to Creating Custom UI Components. The basic steps for including Ajax in a custom component are:
The next section describes the example used in this tutorial. When reading this section, you'll see how all the pieces listed in the preceding steps fit together. The Editable Label ExampleThe editable label example represents a classic use case of Ajax technology. This example uses a custom label component that, when you click on it in the page, renders an input component and a button. When you enter a string of characters into the input field and click the button, the label reappears with the string you entered. The rest of the page stays the same; no refresh of the page occurs. Figure 2: Screen shot of the Editable Label Example Running the ExampleYou can see a demo of this example at the Java Blueprints site on java.net. Go to Library 2 and look for Dynamic Text Label. To run the example, you need to download the Java Blueprints Solutions Catalog for Java EE 5 bundle. To do this, follow these steps:
|
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> |
dl:dlabel tag represents one of the label
components. Note
that the data for each component is bound to the backing bean
called SessionBean. 
The following steps explain the architecture illustrated in Figure 3:
index.jsp page contains an HTML script
tag
rendered by the renderer, DLabelRenderer. While
performing the rendering of the components, DLabelRenderer
also creates a hash map with all the component IDs and values.
faces/ajax-dlabel-script.js,
which is
mapped to a FacesServlet instance. This instance
processes the DLabelPhaseListener instance, which
recognizes the URL and returns the script.js
page
containing the client-side JavaScript code necessary for the Ajax
interactions. When the page loads, it is initialized, and the initialize
function is called. This function registers all the
JavaScript
events that are needed for rendering the DLabel component
tags on the page.onclick event.
The updateOnServer JavaScript function, which is mapped
to
this event,
creates an XMLHttpRequest
object and configures it with the URL to the FacesServlet
instance. If the user changed the Name field to Bob, the
URL is faces/ajax-dlabel-update&component-id=Name&component-value=Bob.XMLHttpRequest object makes a call to FacesServlet,
which updates SessionBean.XMLHttpRequest
object makes a call to the FacesServlet instance, passing
the URL faces/ajax-dlabel-update&component-id=Name&component-value=Bob.
The FacesServlet instance processes the DLabelPhaseListener
instance that recognizes the URL the XMLHttpRequest
object passed to it. At this point, the FacesServlet
instance also updates the value of the name property in SessionBean.
ks
up the
component ID included in the URL and stores the new dataDLabelPhaseListener
takes the component ID and value that is included in the URL, looks up
the component ID and its value from a hash map, and updates it with the
user's input.DLabelPhaseListener instance generates an XML
document containing the new component ID and value and returns it to
the XMLHttpRequest object.XMLHttpRequest
object updates the HTML DOM with the new dataXMLHttpRequest object calls the XMLHttpRequest
callback function. This
function updates the
HTML DOM based on the contents of the XML document that was returned,
and the response is sent back to the client.onmouseover events occur.dojo.event and dojo.io
packages help
with implementing the Ajax functionality in the application. onmouseover events and to render
the components in response to
onclick events. The JavaScript required to perform
these tasks is
fairly standard. You can get help with it at the JavaScript
Resource Center or elsewhere.script.js file includes one call to the
dojo.event.connect method:
bpui.dlabel = new DLabel(); |
initialize function is
called before the DOJO mechanism initializes. This line also prevents
this component's code from
interfering with the loading of any DOJO widgets.script.js file also uses the dojo.io.bind
method call in a few
places. The io package is used to exchange data
with the
server. This is the package that encapsulates the XMLHttpRequest
mechanism. So, when using the dojo.io.bind
method, you don't need to implement the JavaScript functions that
create, initialize, and configure the XMLHttpRequest
object, and
you are able to hide the calls that XMLHttpRequest makes
to the phase listener. Take a look at the ajax-commons.js
file (Select (as plain text) after clicking the link to
view the file). If you weren't using the dojo.io package, you
would need to
write a script similar to this one to implement the Ajax functionality.onload event is fired,
the
initialize function is called. This function looks
up all the tags
with the class name of dlabelPlainText with the help of
the getElementsByClass
helper function.
Rendering JavaScript Tags with a Custom Renderer
shows how the renderer writes out class name attributes
with this value
on all the component tags. After the initialize
function finds
all the elements with this class name, it will call the updateItem
function, which will attach all necessary JavaScript
events on them.
|
updateOnServer function updates the selected
component's value with
the user input. The following piece of updateOnServer
shows the
parts used to update data on the server.
function updateOnServer(itemId, itemValue) {
|
updateOnServer method passes this set of arguments to
the
dojo.io.bind method:url: This is the URL that the XMLHttpRequest
object passes to the phase listener,
which will
use it to create an XML document with the component IDs and values.method: This indicates the HTTP method to use when
the function
is called. In this case, we want to use POST to post data to the
server.content: This attribute contains the ID of the
component the user
chose to edit as well as the value the user entered into the text field.mimetype: Indicates the MIME type of the content to
be passed
from the phase listenerload: Specifies the function that will be
invoked after the
XML data is received.updateOnServer function calls processUpdateResponse
only after it receives the XML data from the phase listener.
Because of this, the client is not updated until the server indicates
that the data was updated. This way, the data on the client
matches the data on the server.updateOnServer calls
processUpdateResponse it passes to it the XML data. updateItem so that it can be updated in the page.:
function processUpdateResponse(responseXML) {
|
script tag that refers to the script.js file.index.jsp and confirmation.jsp pages of
the Editable Label application include
several dLabel tags. The encodeEnd
method of
DLabelRenderer will be called once for each component tag
in the
page. However, we want to render the script tags
only once for
the entire page. To accomplish this, DLabelRenderer
sets the
RENDERED_SCRIPT_KEY request attribute.
encodeEnd method of DLabelRenderer
invokes the renderScriptOnce
method of DLabelRenderer. This method writes out
the JavaScript
tags to the ResponseWriter instance. Before
it renders the
script tags, it checks the value of RENDERED_SCRIPT_KEY
to determine if
the script
tag has already been rendered:
private void renderScriptOnce(ResponseWriter writer, |
renderScriptOnce method renders two JavaScript
tags. Each one
has a different URL that maps to the FacesServlet
instance, by virtue of the
fact that the URLs have faces/ appended to the front of
them.
Here is the code that writes out on of the script tags to
the page:
writer.startElement("script", component);
|
src attributes of the
tags to determine
what processing it will
perform. The actual JavaScript functions are kept out of the page.DLabelRenderer completes writing the output to ResponseWriter
instance, it
saves the component ID and its value into a hash map and puts the
hash map into the servlet context:
|
DLabelPhaseListener, described
in the next section, will use this hash map to retrieve a particular
component ID and value so that it can update it.DLabelRenderer renders the components themselves
inside of div
tags and sets the div tags' ID attributes to the
components' IDs.
This is because a JavaScript function looks for a tag in a page using
the unique IDs of
div tags. Notice that the renderer writes out a
class attribute with the value dlabelPlainText.
Recall from Registering JavaScript Events on
the Components
that the initialize function looks for any elements with
this class name and registers JavaScript events on them.
writer.startElement("div", component);
|
PhaseListener implementation is used
to detect when
phases of the JavaServer Faces life cycle have begun or
completed. For example, when you implement the
afterPhase(PhaseEvent) method of PhaseListener,
you can perform
some
processing that will execute after each phase or a particular phase of
the life cycle. This processing can include bypassing the normal
JavaServer Faces life cycle rendering mechanism. PhaseListener instance to bypass the life cycle so that
submission of
the page is prevented before Ajax can make changes to the page. A
typical PhaseListener implementation checks the URLs it
receives from
the script tags to determine how it will handle an Ajax
request. DLabelPhaseListener does
one of the
following:DPhaseListener keeps a set of keys to hold the possible
URLs that it
will receive:
private static final String SCRIPT_VIEW_ID = "ajax-dlabel-script.js"; |
afterPhase method, DLabelPhaseListener
obtains the URL from the
view ID that identifies the root of the page's UI component tree.
The first time the page is requested, the URL of the view ID is
ajax-dlabel-script.js. In this case the handleResourceReqest
method is invoked with script.js:
public void afterPhase(PhaseEvent event) {
|
handleResourceRequest method creates a connection to
the script.js
and dojo.js files and streams them to the response.
Once it is finished with
this, it calls the responseComplete method, which
bypasses the rest of
the JavaServer Faces life cycle.DLabelPhaseListener by way of the XMLHttpRequest
object. updateOnServer function is invoked. This
function passes the
URL faces/ajax-dlabel-update to DLabelPhaseListener
by way of the
XMLHttpRequest object. When its afterPhase
method is invoked
during the life cycle, DLabelPhaseListener finds the URL
in the view ID
and executes its handleAjaxRequest method:
private static final String UPDATE_STATE_ID = "ajax-dlabel-update"; |
handleAjaxRequest method gets the component ID and
value from the
request parameters.
FacesContext context = event.getFacesContext(); |
ValueExpression valueBinding = (ValueExpression) |
handleAjaxRequest creates the XML output with
the component ID, compId,
and component value, compValue, and sends the XML to the
response, as shown in
the following code.
String message = "success"; |
updateOnServer
by way of the XMLHttpUpdateResponse object. The updateOnServer
function then passes the XML data to the
processUpdateResponse
JavaScript function. The
JavaScript functions will update the page with the new value. |
| ||||||||||||