Using Child Components and Facets

Encoding JavaScript to Avoid Server Roundtrips

The spinner component performs a roundtrip to the server every time you click one of its buttons. That roundtrip updates the spinner's value on the server. Those roundtrips can take a severe bite out of the spinner's performance, so in almost all circumstances, it is better to store the spinner's value on the client and update the component's value only when the form in which the spinner resides is submitted. We can do that with JavaScript that looks like this:

  <input type="text" name="_id1:monthSpinner" value="0"/>   <script language="JavaScript">      document.forms['_id1']['_id1:monthSpinner'].spin = function (increment) {         var v = parseInt(this.value) + increment;         if (isNaN(v)) return;         if ('min' in this && v < this.min) return;         if ('max' in this && v > this.max) return;            this.value = v;      };      document.forms['_id1']['_id1:monthSpinner'].min = 0;   </script>   <input type="button" value="<"         onclick="document.forms['_id1']['_id1:monthSpinner'].spin(-1);"/>   <input type="button" value=">"         onclick="document.forms['_id1']['_id1:monthSpinner'].spin(1);"/>     

When you write JavaScript code that accesses fields in a form, you need to have access to the form ID, such as '_id1' in the expression

  document.forms['_id1']['_id1:monthSpinner']

The second array index is the client ID of the component.

Obtaining the form ID is a common task, and we added a convenience method to the com.corejsf.util.Renderers class for this purpose:

  public static String getFormId(FacesContext context, UIComponent component) {      UIComponent parent = component;      while (!(parent instanceof UIForm)) parent = parent.getParent();      return parent.getClientId(context);   }     

We will not go into the details of JavaScript programming here, but note that we are a bit paranoid about injecting global JavaScript functions into an unknown page. We do not want to risk name conflicts. Fortunately, JavaScript is a well-designed language with a flexible object model. Rather than writing a global spin function, we define spin to be a method of the text field object.

JavaScript lets you enhance the capabilities of objects on-the-fly by adding methods and fields. We use the same approach with the minimum and maximum values of the spinner, adding min and max fields if they are required.

The spinner renderer that encodes the preceding JavaScript is shown in Listing 9-15.

Note that the UISpinner component is completely unaffected by this change. Only the renderer has been updated, thus demonstrating the power of pluggable renderers.

Listing 9-15. spinner-js/src/java/com/corejsf/JSSpinnerRenderer.java

  1. package com.corejsf;   2.   3. import java.io.IOException;   4. import java.text.MessageFormat;   5. import java.util.Map;   6. import javax.faces.component.EditableValueHolder;   7. import javax.faces.component.UIComponent;   8. import javax.faces.component.UIInput;   9. import javax.faces.context.FacesContext;  10. import javax.faces.context.ResponseWriter;  11. import javax.faces.convert.ConverterException;  12. import javax.faces.render.Renderer;  13.  14. public class JSSpinnerRenderer extends Renderer {  15.    public Object getConvertedValue(FacesContext context, UIComponent component,  16.          Object submittedValue) throws ConverterException {  17.       return com.corejsf.util.Renderers.getConvertedValue(context, component,  18.          submittedValue);  19.    }  20.  21.    public void encodeBegin(FacesContext context, UIComponent component)  22.          throws IOException {  23.      ResponseWriter writer = context.getResponseWriter();  24.      String clientId = component.getClientId(context);  25.      String formId = com.corejsf.util.Renderers.getFormId(context, component);  26.  27.      UIInput spinner = (UIInput)component;  28.      Integer min = (Integer) component.getAttributes().get("minimum");  29.      Integer max = (Integer) component.getAttributes().get("maximum");  30.      Integer size = (Integer) component.getAttributes().get("size");  31.  32.      writer.startElement("input", spinner);  33.      writer.writeAttribute("type", "text", null);  34.      writer.writeAttribute("name", clientId , null);  35.      writer.writeAttribute("value", spinner.getValue().toString(), "value");  36.      if (size != null)  37.          writer.writeAttribute("size", size , null);  38.      writer.endElement("input");  39.  40.      writer.write(MessageFormat.format(  41.         "<script language=\"JavaScript\">"  42.         + "document.forms[''{0}''][''{1}''].spin = function (increment) '{'"  43.         + "var v = parseInt(this.value) + increment;"  44.         + "if (isNaN(v)) return;"  45.         + "if (\"min\" in this && v < this.min) return;"  46.         + "if (\"max\" in this && v > this.max) return;"  47.         + "this.value = v;"  48.         + "};",  49.         new Object[] { formId, clientId } ));  50.  51.       if (min != null) {  52.          writer.write(MessageFormat.format(  53.             "document.forms[''{0}''][''{1}''].min = {2};",  54.             new Object[] { formId, clientId, min }));  55.       }  56.       if (max != null) {  57.          writer.write(MessageFormat.format(  58.             "document.forms[''{0}''][''{1}''].max = {2};",  59.             new Object[] { formId, clientId, max }));  60.       }  61.       writer.write("</script>");  62.  63.       writer.startElement("input", spinner);  64.       writer.writeAttribute("type", "button", null);  65.       writer.writeAttribute("value", "<", null);  66.       writer.writeAttribute("onclick",  67.          MessageFormat.format(  68.             "document.forms[''{0}''][''{1}''].spin(-1);",  69.             new Object[] { formId, clientId }),  70.             null);  71.       writer.endElement("input");  72.  73.       writer.startElement("input", spinner);  74.       writer.writeAttribute("type", "button", null);  75.       writer.writeAttribute("value", ">", null);  76.       writer.writeAttribute("onclick",  77.          MessageFormat.format(  78.             "document.forms[''{0}''][''{1}''].spin(1);",  79.             new Object[] { formId, clientId }),  80.             null);  81.       writer.endElement("input");  82.      }  83.  84.      public void decode(FacesContext context, UIComponent component) {  85.        EditableValueHolder spinner = (EditableValueHolder) component;  86.        Map<String, String> requestMap  87.           = context.getExternalContext().getRequestParameterMap();  88.        String clientId = component.getClientId(context);  89.        spinner.setSubmittedValue((String) requestMap.get(clientId));  90.        spinner.setValid(true);  91.      }  92.  }     



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