Phase Events

Passing Data from the UI to the Server

The two flags in the application shown in Figure 7-8 are implemented with links. The link for the German flag is listed in the previous section. Here is the link for the British flag:

  <h:commandLink action="#{localeChanger.englishAction}" immediate="true">      <h:graphicImage value="/british_flag.gif" style="border: 0px"/>   </h:commandLink>

Notice that each link has a different action: localeChanger.englishAction for the British flag and localeChanger.germanAction for the German flag. The implementations of those actions are minor:

  public class ChangeLocaleBean {      public String germanAction() {         FacesContext context = FacesContext.getCurrentInstance();         context.getViewRoot().setLocale(Locale.GERMAN);         return null;      }      public String englishAction() {         FacesContext context = FacesContext.getCurrentInstance();         context.getViewRoot().setLocale(Locale.ENGLISH);         return null;      }   }

Each listener sets the locale of the view root and returns null to indicate that the JSF implementation should reload the same page. Pretty simple.

But imagine if we supported many languages for example, if we supported 100 languages, we would have to implement 100 actions, and each action would be identical to all the others except for the locale that it would set. Not so simple.

To reduce redundant code that we must write and maintain, it's better to pass the language code from the UI to the server. That way, we can write a single action or action listener to change the view root's locale. JSF gives us three convenient mechanisms to pass information from the UI to the server, in the form of JSP tags:

  • f:param

  • f:setPropertyActionListener

  • f:attribute

Now we take a look at each tag in turn to see how we can eliminate redundant code.

The f:param Tag

The f:param tag lets you attach a parameter to a component. Interestingly enough, the f:param tag behaves differently depending upon the type of component to which it is attached. For example, if you attach an f:param tag to an h:outputText, the JSF implementation uses the parameter to fill in placeholders, such as {0}, {1}, etc. If you attach an f:param tag to a command component, such as a button or a link, the JSF implementation passes the parameter's value to the server as a request parameter. Here is how we can use the f:param tag for our flag example:

  <h:commandLink immediate="true"      action="#{localeChanger.changeLocale}">      <f:param name="languageCode" value="de"/>      <h:graphicImage value="/german_flag.gif" style="border: 0px"/>   </h:commandLink>   ...   <h:commandLink immediate="true"      action="#{localeChanger.changeLocale}">      <f:param name="languageCode" value="en"/>      <h:graphicImage value="/british_flag.gif" style="border: 0px"/>   </h:commandLink>

On the server, we access the languageCode request parameter to set the locale:

  public class ChangeLocaleBean {      public String changeLocale() {         FacesContext context = FacesContext.getCurrentInstance();         String languageCode = getLanguageCode(context);         context.getViewRoot().setLocale(new Locale(languageCode));         return null;      }      private String getLanguageCode(FacesContext context) {         Map<String, String> params = context.getExternalContext().             getRequestParameterMap();         return params.get("languageCode");      }   }

No matter how many flags links we add to our JSP page, our ChangeLocaleBean is finished. No more redundant code.

The f:attribute Tag

Another way to pass information from the UI to the server is to set a component's attribute with the f:attribute tag. Here is how we do that with our flag example:

  <h:commandLink immediate="true"      actionListener="#{localeChanger.changeLocale}">      <f:attribute name="languageCode" value="de"/>      <h:graphicImage value="/german_flag.gif" style="border: 0px"/>   </h:commandLink>   ...   <h:commandLink immediate="true"      actionListener="#{localeChanger.changeLocale}">      <f:attribute name="languageCode" value="en"/>      <h:graphicImage value="/british_flag.gif" style="border: 0px"/>   </h:commandLink>

There are two things to notice here. First, we are using f:attribute to set an attribute on the link. That attribute's name is languageCode and its value is either en or de.

Second, we have switched from an action to an action listener. That is because action listeners are passed an event object that gives us access to the component that triggered the event; of course, that is one of our links. We need that component to access its languageCode attribute. Here is how it all hangs together on the server:

  public class ChangeLocaleBean {      public void changeLocale(ActionEvent event) {         UIComponent component = event.getComponent();         String languageCode = getLanguageCode(component);         FacesContext.getCurrentInstance()             .getViewRoot().setLocale(new Locale(languageCode));      }      private String getLanguageCode(UIComponent component) {         Map<String, Object> attrs = component.getAttributes();         return (String) attrs.get ("languageCode");      }   }

This time, instead of pulling the language code out of a request parameter, we pull it out of a component attribute. Either way, the ChangeLocaleBean's implementation is finished, no matter how many locales we support.

The f:setPropertyActionListener Tag

As we have seen, f:param and f:attribute are handy for passing information from the UI to the server, but those tags require us to manually dig the information out from a request parameter or component attribute, respectively.

The f:setPropertyActionListener tag, new for JSF 1.2, puts an end to that digging. With f:setPropertyActionListener, the JSF implementation sets a property in your backing bean for you. Here is how it works for our flags example:

  <h:commandLink immediate="true"      action="#{localeChanger.changeLocale}">      <f:setPropertyActionListener target="#{localeChanger.languageCode}"         value="de"/>      <h:graphicImage value="/german_flag.gif" style="border: 0px"/>   </h:commandLink>   ...   <h:commandLink immediate="true"      action="#{localeChanger.changeLocale}">      <f:setPropertyActionListener target="#{localeChanger.languageCode}"         value="en"/>      <h:graphicImage value="/british_flag.gif" style="border: 0px"/>   </h:commandLink>

In the preceding JSP code, we tell the JSF implementation to set the languageCode property of the localeChanger bean with either de or en. Here is the corresponding implementation of the localeChanger bean:

  public class ChangeLocaleBean {      private String languageCode;      public String changeLocale() {         FacesContext context = FacesContext.getCurrentInstance();         context.getViewRoot().setLocale(new Locale(languageCode));         return null;      }      public void setLanguageCode(String newValue) {         languageCode = newValue;      }   }

For this implementation of the ChangeLocaleBean, we provide a languageCode readonly property that is set by the JSF implementation.

In the context of this example, f:setPropertyActionListener is ostensibly the best choice for setting the localeChanger bean's languageCode property because it results in the simplest implementation of the ChangeLocaleBean class. However, f:param and f:attribute have their place in other contexts, to set request parameters or component attributes, respectively.

So far in this chapter, we have seen how to attach event handling to component instances. JSF also lets you specify global event handlers that are invoked at different points in the JSF life cycle. Those events are the focus of the next section.



Core JavaServerT Faces
Core JavaServer(TM) Faces (2nd Edition)
ISBN: 0131738860
EAN: 2147483647
Year: 2004
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net