The Java EE 5 Tutorial

Registering an Action Listener on a Component

A page author can register an ActionListener implementation on a UICommand component by nesting an actionListener tag within the component’s tag on the page. Similarly to the valueChangeListener tag, the actionListener tag supports both the type and binding attributes. A page author must use one of these attributes to reference the action listener.

Duke’s Bookstore does not use any ActionListener implementations. Here is one of the commandLink tags on the chooselocale.jsp page, changed to reference an ActionListener implementation rather than a backing bean method:

<h:commandLink id="NAmerica" action="bookstore">
     <f:actionListener type="listeners.LocaleChange" />
</h:commandLink>

The type attribute of the actionListener tag specifies the fully qualified class name of the ActionListener implementation. Similarly to the valueChangeListener tag, the actionListener tag also supports the binding attribute. Binding Converters, Listeners, and Validators to Backing Bean Properties explains more about how to bind listeners to backing bean properties.

When this tag’s component is activated, the component’s decode method (or its associated Renderer) automatically queues the ActionEvent implementation associated with the specified ActionListener implementation onto the component.

In addition to the actionListener tag that allows you register a custom listener onto a component, the core tag library includes the 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.jsp page uses setPropertyActionListener with two components: the commandLink component used to link to the bookdetails.jsp page and the commandButton component used to add a book to the cart:

<c:forEach items="#{bookDBAO.books}" var="book"
     varStatus="stat">
    <c:set var="book" scope="request" value="${book}"/>
        ...
    <h:commandLink action="#{catalog.details}"
        value="#{book.title}">
        <f:setPropertyActionListener
             target="#{requestScope.book}" value="#{book}"/>
    </h:commandLink>
    ...
    <h:commandButton id="add"
        action="#{catalog.add}" value="#{bundle.CartAdd}">
        <f:setPropertyActionListener
             target="#{requestScope.book}" value="#{book}"/>
    </h:commandButton>
    <c:remove var="book" scope="request"/>
</c:forEach>

As shown in the preceding code, the commandLink and commandButton components are within a forEach 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 a forEach 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.jsp or activates the commandButton component to go to bookcatalog.jsp, the book data is available to those pages. Therefore, the 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 setPropertyActionListener tag’s value attribute references the book object. The 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.