Up to now, we've added action and value change listeners to components with the actionListener and valueChangeListener attributes, respectively. However, you can also add action and value change listeners to a component with the f:actionListener and f:valueChangeListener tags. Typically, you use those tags when you need multiple action or value change listeners for a single component. In Listing 7-1 on page 278, we defined a menu like this:
<h:selectOneMenu value="#{form.country}" onchange="submit()" valueChangeListener="#{form.countryChanged}"> <f:selectItems value="#{form.countryNames}"/> </h:selectOneMenu> Alternatively, we could use f:valueChangeListener, like this:
<h:selectOneMenu value="#{form.country}" onchange="submit()"> <f:valueChangeListener type="com.corejsf.CountryListener"/> <f:selectItems value="#{form.countryNames}"/> </h:selectOneMenu> Notice the difference between the values specified for the valueChangeListener attribute and the f:valueChangeListener tag. The former specifies a method binding, whereas the latter specifies a Java class. For example, the class referred to in the previous code fragment looks like this:
public class CountryListener implements ValueChangeListener { private static final String US = "United States"; public void processValueChange(ValueChangeEvent event) { FacesContext context = FacesContext.getCurrentInstance(); if (US.equals((String) event.getNewValue())) context.getViewRoot().setLocale(Locale.US); else context.getViewRoot().setLocale(Locale.CANADA); } } Like all listeners specified with f:valueChangeListener, the preceding class implements the ValueChangeListener interface. That class defines a single method: void processValueChange(ValueChangeEvent). The f:actionListener tag is analogous to f:valueChangeListener the former also has a type attribute that specifies a class name; the class must implement the ActionListener interface. For example, in Listing 7-6 on page 284, we defined a button like this:
<h:commandButton image="mountrushmore.jpg" actionListener="#{rushmore.listen}" action="#{rushmore.act}"/> Instead of using the actionListener attribute to define our listener, we could have used the f:actionListener tag instead:
<h:commandButton image="mountrushmore.jpg" action="#{rushmore.act}"> <f:actionListener type="com.corejsf.RushmoreListener"/> </h:commandButton> The class specified by f:actionListener in the preceding code fragment looks like this:
public class ChangeLocaleBean implements ActionListener { public void processAction(ActionEvent e) { FacesContext context = FacesContext.getCurrentInstance(); Map requestParams = context.getExternalContext().getRequestParameterMap(); String locale = (String) requestParams.get("locale"); if ("english".equals(locale)) context.getViewRoot().setLocale(Locale.UK); else if("german".equals(locale)) context.getViewRoot().setLocale(Locale.GERMANY); } } Action listener classes must implement the ActionListener interface, which defines a processAction method. You can also specify multiple listeners with multiple f:actionListener or f:valueChangeListener tags per component. For example, we could add another action listener to our previous example like this:
<h:commandButton image="mountrushmore.jpg" action="#{rushmore.act}"> <f:actionListener type="com.corejsf.RushmoreListener"/> <f:actionListener type="com.corejsf.ActionLogger"/> </h:commandButton> In the preceding code fragment, the ActionLogger class is a simple action listener that logs action events. If you specify multiple listeners for a component, as we did in the preceding code fragment, the listeners are invoked in the following order: The listener specified by the listener attribute Listeners specified by listener tags, in the order they are declared
javax.faces.event.ValueChangeListener
javax.faces.event.ActionListener NOTE | You may wonder why you must specify a method binding for listeners when you use the actionListener and valueChangeListener attributes and why you must use a class name for listeners specified with f:actionListener and f:valueChangeListener tags. The truth is that the mismatch between listener attributes and tags was an oversight on the part of the JSF expert group. |
|