Parameters and Bindings

You may create a component that has parameters. Under Tapestry, component parameters are a kind of "named slot" that can be wired up as a source (or sink) of data in a number of ways. This "wiring up" is actually accomplished using binding objects.

[Tip]Connected Parameters

Most components use "in" parameters and can have Tapestry connect the parameters to properties of the component automatically. This discussion reveals some inner workings of Tapestry that developers most often no longer need to be aware of.

The page loader, the object that converts a component specification into an actual component, is responsible for creating and assigning the bindings. It uses the method setBinding() to assign a binding with a name. Your component can retrieve the binding by name using getBinding().

For example, lets create a component that allows the color of a span of text to be specified using a java.awt.Color object. The component has a required parameter named color. The class's renderComponent() method is below:

protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
  throws RequestCycleException
{
  IBinding colorBinding = getBinding("color");
  Color color = (Color)colorBinding.getObject("color", Color.class);
  String encodedColor = RequestContext.encodeColor(color);

  writer.begin("font");
  writer.attribute("color", encodedColor);

  renderWrapped(writer, cycle);

  writer.end();
}

The call to getBinding() is relatively expensive, since it involves rummaging around in a Map and then casting the result from java.lang.Object to org.apache.tapestry.IBinding.

Because bindings are typically set once and then read frequently by the component, implementing them as private instance variables is much more efficient. Tapestry allows for this as an optimization on frequently used components.

The setBinding() method in AbstractComponent checks to see if there is a read/write JavaBeans property named "nameBinding" of type IBinding. In this example, it would look for the methods getColorBinding() and setColorBinding().

If the methods are found, they are invoked from getBinding() and setBinding() instead of updating the Map.

This changes the example to:

private IBinding colorBinding;

public void setColorBinding(IBinding value)
{
  colorBinding = value;
}

public IBinding getColorBinding()
{
  return colorBinding;
}


protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
  throws RequestCycleException
{
  Color color = (Color)colorBinding.getObject("color", Color.class);
  String encodedColor = RequestContext.encodeColor(color);

  writer.begin("font");
  writer.attribute("color", encodedColor);

  renderWrapped(writer, cycle);

  writer.end();
}

This is a trade off; slightly more code for slightly better performance. There is also a memory bonus; the Map used by AbstractComponent to store the binding will never be created.