ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Handling Events in JavaServer Faces, Part 2
Pages: 1, 2

Triggering an Event by Changing a Value

When the user changes the value of an input component, a ValueChangeEvent is fired when the form is submitted. You have similar options for handling a ValueChangeEvent as you have for an ActionEvent: use a value change listener method binding or attach one or more ValueChangeListener to the component:



<!-- Using a method binding expression -->
<h:selectBooleanCheckbox valueChangeListener="#{myBean.handleNewValue}" />

<!-- Using one or more listeners -->
<h:selectBooleanCheckbox>
  <f:valueChangeListener type="com.mycompany.LogEventListener" />
  <f:valueChangeListener type="com.mycompany.HandleNewValueListener" />
</h:selectBooleanCheckbox>

Two things make the JSF ValueChangeEvent less important than similar events in a traditional GUI framework: it fires only when the form is submitted (because that's when the server can detect the change), and JSF's mechanisms for validation and automatic model updates handle most of the typical use cases. That said, it's still useful for some features, especially if you know that your users use JavaScript-enabled browsers and are connected to the server via a high-speed connection so frequent requests don't cause performance problems.

In this section, we look at how to use a ValueChangeEvent triggered by a change in a checkbox value to switch between the standard and extended report entry type choices. Example 8-6 shows the entry form page modified for this purpose.

Example 8-6. Entry form area JSP page with a checkbox for extending the type choices (expense/stage4/entryFormArea.jsp)

<%@ page contentType="text/html" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>

<f:view>
  <h:form>
    Title: 
    <h:inputText id="title" size="30" required="true"
      value="#{reportHandler.currentReport.title}" />
    <h:message for="title" />
    <br>
    Entry:
    <br>
    Date:
    <h:inputText id="date" size="8" required="true"
      value="#{entryHandler.currentEntry.date}">
      <f:convertDateTime  dateStyle="short" />
    </h:inputText>
    <h:message for="date" />
    <br>
    Type:
    <h:selectOneMenu id="type" required="true"
      value="#{entryHandler.currentEntry.type}">
      <f:selectItems value="#{entryHandler.currentChoices}"/>
    </h:selectOneMenu>
    Extended Choices:
    <h:selectBooleanCheckbox immediate="true" onchange="this.form.submit( );"
       valueChangeListener="#{entryHandler.toggleTypes}" />
    <h:message for="type" />
    <br>
    Amount:
    <h:inputText id="amount" size="8" required="true"
      value="#{entryHandler.currentEntry.amount}">
      <f:convertNumber pattern="#,##0.00" />
      <f:validateDoubleRange minimum="1"/>
    </h:inputText>
    <h:message for="amount" />
    <br>
    <h:commandButton value="Add"
      disabled="#{reportHandler.addEntryDisabled}"
      action="#{entryHandler.add}" />
  </h:form>
  <h:messages layout="table" globalOnly="true" />

  <%-- Loop to verify that it works --%>
  <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
  <ol>
    <c:forEach items="${reportHandler.currentReportEntries}" var="e">
      <li>Date: ${e.date}, Type: ${e.type}, Amount: ${e.amount}</li>
    </c:forEach>
  </ol>
</f:view>

The <h:commandButton> element is replaced with an <h:selectBooleanCheckbox> element in Example 8-6. Its immediate attribute is set to true, causing the ValueChangeEvent to fire in the Apply Request Values phase instead of in the Process Validations phase. This means that we can handle the event without causing any validation error messages to be displayed.

The onchange attribute contains JavaScript that submits the form the checkbox belongs to when its value is changed, so that the user doesn't have to click on any button for the change to take effect.

Finally, the valueChangeListener attribute binds the component to a value change listener method in the entryHandler bean. This method looks almost the same as the toggleTypes() method used for the Ext/Std button in Example 8-4, but it has a different signature:

package com.mycompany.expense;

import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
...
public class EntryHandler {
    ...
    public void toggleTypes(ValueChangeEvent event) {
        includeSpecial = !includeSpecial;
        FacesContext.getCurrentInstance( ).renderResponse( );
    }
    ...
}

A value change listener method is a method with a ValueChangeEvent as its single parameter and a void return type. The toggleType( ) method used here doesn't use the event at all. It just flips the includeSpecial flag, the same as the method used in the previous section. What's different is that it also tells JSF to jump straight to the Render Response phase by calling the FacesContext renderResponse() method. For an action method, this happens automatically, but for all other method binding method types you must do so explicitly when needed. The rest remains the same as when we used a button to trigger the type list changes.

The event handling concepts and mechanisms that I've described in this chapter may take some time to truly understand, but when you do, they make sense given the nature of a web application with the client separated from the server. In the next chapter, we'll add to what you've learned here, looking at how to tell JSF to switch to a new view depending on the event-handling outcome.

Hans Bergsten is the founder of Gefion Software and author of O'Reilly's JavaServer Pages, 3rd Edition.


Return to ONJava.com.