An application developer can implement listeners as classes or as
managed bean methods. If a listener is a managed bean method, the page
author references the method from either the component’s
valueChangeListener attribute or its actionListener attribute. If
the listener is a class, the page author can reference the listener from
either an f:valueChangeListener tag or an f:actionListener tag and
nest the tag inside the component tag to register the listener on the
component.
This section explains how to register a NameChanged value-change
listener and a BookChange action listener implementation on
components. The Duke’s Bookstore case study includes both of these
listeners.
Registering a Value-Change Listener on a Component
A page author can register a ValueChangeListener implementation on a
component that implements EditableValueHolder by nesting an
f:valueChangeListener tag within the component’s tag on the page. The
f:valueChangeListener tag supports the attributes shown in
Table 11-5, one of which must be used.
Table 11-5 Attributes for the f:valueChangeListener Tag
Attribute |
Description |
type
|
References the fully qualified class name of a
ValueChangeListener implementation. Can accept a literal or a value
expression. |
binding
|
References an object that implements ValueChangeListener.
Can accept only a value expression, which must point to a managed bean
property that accepts and returns a ValueChangeListener
implementation. |
The following example shows a value-change listener registered on a
component:
<h:inputText id="name"
size="30"
value="#{cashierBean.name}"
required="true"
requiredMessage="#{bundle.ReqCustomerName}">
<f:valueChangeListener
type="javaeetutorial.dukesbookstore.listeners.NameChanged" />
</h:inputText>
In the example, the core tag type attribute specifies the custom
NameChanged listener as the ValueChangeListener implementation
registered on the name component.
After this component tag is processed and local values have been
validated, its corresponding component instance will queue the
ValueChangeEvent associated with the specified ValueChangeListener
to the component.
Registering an Action Listener on a Component
A page author can register an ActionListener implementation on a
command component by nesting an f:actionListener tag within the
component’s tag on the page. Similarly to the f:valueChangeListener
tag, the f:actionListener tag supports both the type and binding
attributes. One of these attributes must be used to reference the action
listener.
Here is an example of an h:commandLink tag that references an
ActionListener implementation:
<h:commandLink id="Duke" action="bookstore">
<f:actionListener
type="javaeetutorial.dukesbookstore.listeners.LinkBookChangeListener" />
<h:outputText value="#{bundle.Book201}"/>
</h:commandLink>
The type attribute of the f:actionListener tag specifies the fully
qualified class name of the ActionListener implementation. Similarly
to the f:valueChangeListener tag, the f:actionListener tag also
supports the binding attribute. See
Binding Converters, Listeners, and
Validators to Managed Bean Properties for more information about
binding listeners to managed bean properties.
In addition to the actionListener tag that allows you register a
custom listener onto a component, the core tag library includes the
f:setPropertyActionListener tag. You use this tag to register a
special action listener onto the ActionSource instance associated with
a component. When the component is activated, the listener will store
the object referenced by the tag’s value attribute into the object
referenced by the tag’s target attribute.
The bookcatalog.xhtml page of the Duke’s Bookstore application uses
f:setPropertyActionListener with two components: the h:commandLink
component used to link to the bookdetails.xhtml page and the
h:commandButton component used to add a book to the cart:
<h:dataTable id="books"
value="#{store.books}"
var="book"
headerClass="list-header"
styleClass="list-background"
rowClasses="list-row-even, list-row-odd"
border="1"
summary="#{bundle.BookCatalog}" >
...
<h:column>
<f:facet name="header">
<h:outputText value="#{bundle.ItemTitle}"/>
</f:facet>
<h:commandLink action="#{catalog.details}"
value="#{book.title}">
<f:setPropertyActionListener target="#{requestScope.book}"
value="#{book}"/>
</h:commandLink>
</h:column>
...
<h:column>
<f:facet name="header">
<h:outputText value="#{bundle.CartAdd}"/>
</f:facet>
<h:commandButton id="add"
action="#{catalog.add}"
value="#{bundle.CartAdd}">
<f:setPropertyActionListener target="#{requestScope.book}"
value="#{book}"/>
</h:commandButton>
</h:column>
The h:commandLink and h:commandButton tags are within an
h:dataTable tag, which iterates over the list of books. The var
attribute refers to a single book in the list of books.
The object referenced by the var attribute of an h:dataTable tag is
in page scope. However, in this case you need to put this object into
request scope so that when the user activates the commandLink
component to go to bookdetails.xhtml or activates the commandButton
component to go to bookcatalog.xhtml, the book data is available to
those pages. Therefore, the f:setPropertyActionListener tag is used to
set the current book object into request scope when the commandLink or
commandButton component is activated.
In the preceding example, the f:setPropertyActionListener tag’s
value attribute references the book object. The
f:setPropertyActionListener tag’s target attribute references the
value expression requestScope.book, which is where the book object
referenced by the value attribute is stored when the commandLink or
the commandButton component is activated.