Recall the
login and
login-ajax examples from chapter 1.
They have some fundamental differences:
login |
login-ajax |
Login button has an action attribute |
Login button does not have an action attribute |
Does an entire form submit upon click |
Only sends name and password upon click |
Navigates from index.xhtml to welcome.xhtml |
Stays in index.xhtml throughout |
Requires a "page flip" before response is rendered |
Asynchronously updates one component of index.xhtml |
The performance of
login-ajax is accomplished
through
Asynchronous JavaScript with XMLHttpRequest (Ajax).
JSF 2.0 has built-in support for Ajax.
JSF integrates Ajax into its life cycle, which is at the center of
all JSF applications.
That deep level of integration lets
you handle Ajax requests in the same manner in which you handle other
component behaviors, such as validation or conversion.
To integrate Ajax, JSF divides its 6-phase life cycle into two
parts: an
execute portion and a
render portion.
When JSF "executes" a component on the server, it:
- Converts and validates the component’s value (if the component is an
input)
- Pushes valid input values to the model (if the component is wired to a
bean property)
- Executes actions and action listeners (if the component is an
action):
When JSF "renders" a component, it codes the component in HTML for
display in a client browser.
JSF always executes components first, and subsequently renders them:
For regular HTTP requests, all components in a form are both executed
and rendered.
For Ajax requests, JSF executes one or more
components, and renders zero or more components.
So Ajax requests differ from regular HTTP requests in only two ways:
- Ajax partially processes forms on the server during the
Ajax call.
- Ajax partially renders Document Object Model (DOM)
elements on the client after the Ajax call returns from the
server.
On any given Ajax request, you specify a set of components that JSF
executes, and another set of components that it
renders:
- Associate a component and an event with an Ajax request.
- Indentify components to execute on the server during the Ajax
request.
- Identify components to render after the Ajax request.
Here is the
Login button element in the
login example:
<h:commandButton value="Login" action="welcome"/>
For the
login-ajax example:
<h:commandButton value="Login">
<f:ajax execute="name password" render="out"/>
</h:commandButton>
Note the use of the
execute="..." and
render="..."
attributes.
Like other tags from JSF’s core library, such as
f:validator
and
f:converter,
f:ajax attaches a
behavior to a
component.
In this case, the behavior is initiated by the event associated
with clicking the command button.
Behavior can be initiated by events attached to input components besides
buttons using the
event="..." attribute:
<h:inputText value="#{someBean.someProperty}">
<f:ajax event="keyup" render="someOtherComponentId"/>
</h:inputText>
Each time a
keyup event occurs in the input text component, some
other component is asynchronously updated.
Note:
- If the execute="..." is missing (as it is in this
case), the component in
which the f:ajax tag is found is executed by default (see
the @this keyword, next)
- Values for the event attribute are the same as Javascript
events without the "on" prefix
Here is JSF code that attaches behavior to an input text field, using
the
execute="@this" attribute, whenever
a
keyup event is fired from a component with id "
name":
<h:inputText id="name" value="#{user.name}">
<f:ajax event="keyup" execute="@this" render="echo"/>
</h:inputText>
Upon key up, the
name component will be executed, including
validation and update of the model's
user bean.
A second component, "
echo", is an output text component that is
selectively rendered in the current page.
Its value is the same
user property updated during the execute
part of the cycle:
<h:outputText id="echo" value="#{user.name}"/>
The overall effect is that each character in the name is echoed back to
the browser as it is typed.
JSF executes
@this by default, so
execute="@this" can be
omitted from this example:
<h:inputText id="name" value="#{user.name}">
<f:ajax event="keyup" render="echo"/> <!-- execute="@this" is implicit -->
</h:inputText>
An Ajax
callback is a JavaScript function called at various
times during an Ajax request.
You specify a callback with the
onevent attribute of
the
f:ajax tag. Example:
<f:ajax event="keyup" render="nameError" onevent="showProgress"/>
This is part of a
requestMonitor application that displays a
progress bar as an Ajax request progresses.
To show and hide the progess bar, a
JavaScript library is used.
Below is JSF markup for an input text field that:
- Uses a custom validator to check for illegal underscores each
time a character is entered
- Presents a progress bar while the validation proceeds
#{msgs.namePrompt}
<h:panelGroup>
<h:inputText id="name" value="#{user.name}"
validator="#{user.validateName}">
<f:ajax event="keyup" render="nameError" onevent="showProgress"/>
</h:inputText>
<h:graphicImage id="pole"
library="images" name="orange-barber-pole.gif"
style="display: none"/>
<h:message for="name" id="nameError"
value="#{user.nameError}" style="color: red"/>
</h:panelGroup>
JSF passes a
data object to any JavaScript function (such
as
showProgress)
registered as a callback via
f:ajax’s
onevent
attribute.
That object has a property called
status which is an object that
reveals the following information about an Ajax call:
The
showProgress function must first determine the element ID of
the progress bar image, then either show it or hide it depending on the
request status:
function showProgress(data) {
var inputId = data.source.id
var progressbarId = inputId.substring(0, inputId.length - "name".length)
+ "pole";
if (data.status == "begin")
Element.show(progressbarId);
else if (data.status == "success")
Element.hide(progressbarId);
}
The
Element.show and
Element.hide methods are part of the
JavaScript
Prototype library.
JavaScript libraries are popular for Ajax because they provide useful
utilities that shield programmers from annoying differences between
browsers in dealing with the HTML DOM (document object model).
Prototype
(
prototypejs.org)
is a "JavaScript Framework that aims to ease development of dynamic web
applications."
To use a JavaScript library like Prototype in your JSF pages, include a
tag like this:
<h:outputScript library="javascript" name="prototype-1.6.0.2.js"/>
and include the library in your project's
resources folder.
This section collects some of the example Ajax web applications used in
chapters 1 and 10.