Connected Parameters

In most cases, a developer is not interested in bindings; an easier model for developers is one in which Tapestry uses the parameters and bindings to set properties of the component automatically. Starting in release 2.1, Tapestry includes this behavior, with some constraints and limitations.

Part of the <parameter> specification for a parameter is the direction, which can be one of the following values:

in

Input parameter; the value is drawn from the binding (if bound) and applied to the corresponding component property just before rendering the component.

form

A parameter which matches the semantics of a form component. The parameter is treated like an in parameter when the page is rendering.

When the form containing the component is submitted, the connected property is read (after the component renders), and the value applied to the parameter.

custom

Tapestry does not try to connect the parameter with any property; the component is responsible for accessing the binding and retrieving or setting values.

This type must be used for any kind of output parameter, or for an input parameter where the property may be accessed other than during the rendering of the component.

[Note]Why aren't output parameters connectable?

The problem is the timing of output parameters. Sometimes a parameter is only an output parameter when the containing form is submitted (for example, any of the form related components). Sometimes a parameter is output many times (for example, Foreach) while the component renders.

The latter case may always be handled as custom; the former case may be handled in the future.

Defining a parameter as direction in causes Tapestry to connect the parameter to the corresponding property of the component. The parameter specification must identify the Java type of the property. Properties must be read/write (they must have both getter and setter methods).

Tapestry will set properties from parameters just before rendering the component. After the component renders, the parameters are cleared; they are returned to inital values. Tapestry reads these initial values just before it sets the properties the first time. This makes it very easy to set defaults for optional parameters: just provide a default value for the correspoinding instance variable.

If the property is connected to an invariant binding (a static or field binding), then the property is set just once, and never cleared.

There are times when the parameter name can't be used as the property name. For example, the PageLink component has a page parameter, the name of the page to link to. However, all components already have a page property, the IPage that ultimately contains them. The specification for the PageLink component connects the page parameter to a property named targetPage instead.

Defining a connected parameter as required means that the parameter must be bound and the binding must provide a non-null value. A runtime exception is thrown when a required parameter's binding yields a null value.

The following examples show how to declare and use a parameter:

Example 3.1. Connected Parameter - Specification



<specification ...>

  <parameter name="color" direction="in" java-type="java.awt.Color"/>
  
  ...

Example 3.2. Connected Parameter - Java Code


public class ColorComponent extends AbstractComponent
{
  private Color color = Color.RED;
  
  public Color getColor()
  {
    return color;
  }
    
  public void setColor(Color color)
  {
    this.color = color;
  }
  
  protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
  throws RequestCycleException
  {
    writer.begin("font");
    writer.attribute("color", ^RequestContext;.encodeColor(color);
    
    renderWrapped(writer, cycle);
    
    writer.end();
  }
  
}

In this example, the component writes its content inside a <font> element, with the HTML color attribute set from the color parameter. RequestContext includes a static convienience method for converting from a Color object to an encoded color that will be meaningful to a web browser.

The parameter is optional and defaults to red if not specified (that is, if the parameter is not bound).

At runtime, Tapestry will invoke setColor() first (if the color parameter is bound). It will then invoke renderComponent(). Finally (even if renderComponent() throws an exception) it will invoke setColor() again, to restore it back to the default value, Color.RED.

This code includes a defect: because the parameter is optional, there is nothing to prevent it from being bound to null.