JSF supports event handling throughout the JSF life-cycle.
Events are of two types:
- Events occurring in the browser (client side)
- Events having to do with occurrences during the JSF
life-cycle (server side)
In either case, all JSF events are handled
on the server.
Event listeners can affect the JSF life cycle in one of three ways:
- Let the life cycle proceed normally.
- Call the renderResponse method of the FacesContext
class to skip the rest of the life cycle up to Render
Response.
- Call the responseComplete method of
the FacesContext class to skip the rest of the life cycle
entirely.
The diagram below depicts these effects.
You can provide listeners for two kinds of client-side events:
- Value change events
- Action events
You can specify event listeners using either event
attributes or
event
tags.
Value change events are fired by editable value holders, such
as
h:inputText,
h:selectOneRadio,
and
h:selectManyMenu, when the component’s value changes.
For example, suppose that a form lets the user choose a country from a
menu, and:
- If United States is chosen, the form labels a field with
"State"
- If Canada is chosen, the form labels that field with
"Province"
Use the
valueChangeListener and
onchange attributes with a JSF selection tag:
<h:selectOneMenu value="#{form.country}"
onchange="submit()"
valueChangeListener="#{form.countryChanged}">
<f:selectItems value="#{form.countries}" var="loc"
itemLabel="#{loc.displayCountry}" itemValue="#{loc.country}"/>
</h:selectOneMenu>
See the
valuechange example application.
Action events are fired by buttons and links.
For example, suppose an image is rendered on a page and you want to
navigate to different pages depending on which part of the image is
clicked.
This behavior cannot be accomplished with an
action attribute,
because bean methods associated with actions are not given information
about the mouse click.
However, methods associated with
actionListener attributes are
given information about mouse events.
Key difference:
- action listeners: perform interface logic and do not
participate in navigation handling.
- actions: perform business logic and participate in
navigation handling.
Compare:
<h:selectOneMenu value="#{form.country}" onchange="submit()"
valueChangeListener="#{form.countryChanged}">
<f:selectItems value="#{form.countryNames}"/>
</h:selectOneMenu>
and
<h:selectOneMenu value="#{form.country}" onchange="submit()">
<f:valueChangeListener type="com.corejsf.CountryListener"/>
<f:selectItems value="#{form.countryNames}"/>
</h:selectOneMenu>
Difference:
- The valueChangeListener attribute specifies a method binding
- The f:valueChangeListener tag specifies a Java class that must implement
the ValueChangeListener interface:
public class CountryListener implements ValueChangeListener {
public void processValueChange(ValueChangeEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
if ("US".equals(event.getNewValue()))
context.getViewRoot().setLocale(Locale.US);
else
context.getViewRoot().setLocale(Locale.CANADA);
}
}
The advantage of using event tags is that you can attach multiple
listeners to a component:
<h:commandButton image="mountrushmore.jpg" action="#{rushmore.navigate}">
<f:actionListener type="com.corejsf.RushmoreListener"/>
<f:actionListener type="com.corejsf.ActionLogger"/>
</h:commandButton>
If any of the input fields in the
valuechange example were
required, then because the country menu does a form submit, if a user
wanted to simply change countries, validation error messages would be
issued.
To avoid this,
- make the menu immediate to cause the event to be
handled early in the life-cycle:
<h:selectOneMenu value="#{form.country}" onchange="submit()" immediate="true"
valueChangeListener="#{form.countryChanged}">
<f:selectItems value="#{form.countryNames}"/>
</h:selectOneMenu>
- Have the listener render the response so that other components do not
have a chance to validate:
public void countryChanged(ValueChangeEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
if (US.equals((String) event.getNewValue()))
context.getViewRoot().setLocale(Locale.US);
else
context.getViewRoot().setLocale(Locale.CANADA);
context.renderResponse();
}
JSF does not have a built-in tabbed pane component, so you have two
choices:
- Implement one with custom components (chapter 11)
- Use existing tags — with a backing bean — to create
an ad hoc tabbed pane
The
tabbedpane example illustrates the latter approach.
The JSF implementation fires events, called
phase events, before
and after each life cycle phase.
Those events are handled by
phase listeners.
Since JSF 2.0, more finely-grained
system events have been added
to the life cycle.
Both phase events and systems events give a programmer the ability to
change aspects of the JSF life cycle. Described in chapter 8, they
will not be treated further here.
This section collects the example web applications used in this chapter.