Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: restore

Component parameters are the primary means for a component instance and its container to communicate with each other. Parameters are used to configure component instances.

Div
stylefloat:right
titleRelated Articles
classaui-label
Content by Label
showLabelsfalse
showSpacefalse
titleRelated Articles
cqllabel in ("expressions","component-classes","component-templates","parameters") and space = currentSpace()

In the following example, page is a parameter of the pagelink component. The page parameter tells the pagelink component which page to go to when the user clicks on the rendered hyperlink:

Code Block
languagexml
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
    <t:pagelink page="Index">Go Home</t:pagelink>
</html>

A component may have any number of parameters. Each parameter has a specific name, a specific Java type (which may be a primitive value), and may be optional or required.

Within a component class, parameters are declared by using the @Parameter annotation on a private field, as we'll see below.

Anchor
bindingparameters
bindingparameters

Parameter Bindings

In Tapestry, a parameter is not a slot into which data is pushed: it is a connection between a field of the component (marked with the @Parameter annotation) and a property or resource of the component's container. (Components can be nested, so the container can be either the page or another component.)

Wiki Markup
{float:right}
{panel:title=Contents|background=#eee}
{toc:minLevel=1|maxLevel=2}
{panel}
{float}
 

The connection between a component and a property (or resource) of its container is called a binding. The binding is two-way: the component can read the bound property by reading its parameter field. Likewise, a component that updates its parameter field will update the bound property.

...

The component listed below is a looping component; it renders its body a number of times, defined by its start and end parameters (which set the boundaries of the loop). The component can update a result parameter bound to a property of its container; it will automatically count up or down depending on whether start or end is larger.

Code Block
languagejava
package org.example.app.components;

import org.apache.tapestry5.annotations.AfterRender;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.SetupRender;

public class Count
{
    @Parameter (value="1")
    private int start;

    @Parameter(required = true)
    private int end;

    @Parameter
    private int result;

    private boolean increment;

    @SetupRender
    void initializeValues()

...


    {
        result = start;
        increment = start < end;
    }

    @AfterRender
    boolean next()
    {
        if (increment)
        {
            int newResult = value + 1;

            if (newResult <= end)
            {
                result = newResult;
                return false;
            }
        }
        else
        {
            int newResult= value - 1;
            if (newResult>= end)
            {
                result = newResult;
                return false;
            }
        }
        return true;
    }
}

The name of the parameter is the same as field name (except with leading "_" and "$" characters, if any, removed). Here, the parameter names are "start", "end" and "result".

The component above can be referenced in another component or page template, and its parameters bound:

Code Block
languagexml
<html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
    <p> Merry Christmas: <t:count end="3"> Ho! </t:count>
    </p>
</html>

The end attribute is used to bind the end parameter of the Count component. Here, it is being bound to the string value "3", which is automatically coerced by Tapestry into the int value, 3.

...

Component parameters may also be bound using the @Component annotation inside the component class. (Where conflicts occur, the parameters bound using the Component annotation will take precedence over parameter bindings in the template.)

Anchor
binding-expressions
binding-expressions

Binding Expressions

The value inside the template, "3" in the previous example, is a binding expression.

...

Prefix

Description

asset:

The relative path to an asset file (which must exist)

block:

The id of a block within the template

component:

The id of another component within the same template

context:

Context asset: path from context root

literal:

A literal string

nullfieldstrategy:

Used to locate a pre-defined NullFieldStrategy

message:

Retrieves a string from the component's message catalog

prop:

A property expression to read or update

symbol:

Used to read one of your symbols

translate:

The name of a configured translator

validate:

A validator specification used to create some number of field validators

var:

Allows a render variable of the component to be read or updated

...

For example, the following template code:

Code Block
languagexml
<ul>
    <li t:type="loop" source="1..10" value="index">${index}</li>
</ul>

and the following Java code:

Code Block
languagejava
@Property
private int index;

... could be rewritten as just:

Code Block
languagexml
<ul>
    <li t:type="loop" source="1..10" value="var:index">${var:index}</li>
</ul>

In other words, you don't have to define a property in the Java code. The disadvantage is that render variables don't work with the property expression syntax, so you can pass around a render variable's value but you can't reference any of the value's properties.

...

Property expressions are used to link a parameter of a component to a property of its container. Property expressions can navigate a series of properties and/or invoke methods, as well as several other useful patterns. See Property Expressions Component Parameters.

The default binding prefix in most cases is "prop:", which is why it is usually omitted.

Validate: Bindings

Main Article: Forms and Validation Component Parameters

The "validate:" binding prefix is highly specialized. It allows a short string to be used to create and configure the objects that perform input validation for form control components, such as TextField and Checkbox.

...

Assets bindings are used to specify Assets Component Parameters, static content served by Tapestry. By default, assets are located relative to the component class in your packaged application or module. This can be overridden by prefixing the path with "context:", in which case, the path is a context path from the root of the web application context. Because accessing context assets is relatively common, a separate "context:" binding prefix for that purpose exists (described below).

...

Context bindings are like asset bindings, but the path is always relative to the root of the web application context. This is intended for use inside templates, i.e.:

Code Block
languagexml
  <img src="${context:images/icon.png}"/>

Tapestry will adjust the URL of the image so that it is processed by Tapestry, not the servlet container. It will gain a URL that includes the application's version number, it will have a far-future expires header, and (if the client supports it) its content will be compressed before being sent to the client.

...

Parameters that are required must be bound. A runtime exception occurs if a component has unbound required parameters.

Code Block
languagejava
public class Component{

  @Parameter(required = true)
  private String parameter;

}
Tip

Sometimes a parameter is marked as required, but may still be omitted if the underlying value is provided by some other means. This is the case, for example, with the Select component's value parameter, which may have its underlying value set by contributing a ValueEncoderSource. Be sure to read the component's parameter documentation carefully. Required simply enables checks that the parameter is bound, it does not mean that you must supply the binding in the template (or @Component annotation).

Optional Parameters

Parameters are optional unless they are marked as required.

...

The @Parameter annotation's value element can be used to specify a binding expression that will be the default binding for the parameter if otherwise left unbound. Typically, this is the name of a property that that will compute the value on the fly.

Code Block
languagejava
@Parameter(value="defaultMessage") // or, equivalently, @Parameter("defaultMessage")
private String message;

@Parameter(required=true)
private int maxLength;

public String getDefaultMessage(){ 
	return String.format("Maximum field length is %d.", maxLength);
}

As elsewhere, you may use a prefix on the value. A common prefix to use is the "message:" prefix, to access a localized message.

...

In rare cases, it is desirable to defeat the caching; this can be done by setting the cache() attribute of the @Parameter annotation to false..

Anchor
dontUseSyntax
dontUseSyntax

Don't use the ${...} syntax!

Main Article: Component Templates#Expansions Expansions

You generally should not use the Template Expansion syntax, ${...}, within component parameter bindings. Doing so results in the property inside the braces being converted to an (immutable) string, and will therefore result in a runtime exception if your component needs to update the value (whenever the default or explicit binding prefix is prop: or var:, since such component parameters are two-way bindings).

Section
Column
Code Block
languagexml
titleThis is right
<t:textfield t:id="color" value="color"/>
Column
Code Block
languagexml
titleThis is wrong
<t:textfield t:id="color" value="${color}"/>

The general rule is, only use the ${...} syntax in non-Tapestry-controlled locations in your template, such as in attributes of ordinary HTML elements and in plain-text areas of your template.

Section
Column
Code Block
languagexml
titleThis is right
<img src="${context:images/banner.png}"/>
Column
Code Block
languagexml
titleThis is wrong
<img src="context:images/banner.png"/>

Informal Parameters

Main Article: Supporting Informal Component Parameters

Many components support informal parameters, additional parameters beyond the formally defined parameters. Informal parameters will be rendered into the output as additional attributes on the tag rendered by the component. Generally speaking, components that have a 1:1 relationship with a particular HTML tag (such as <TextField> and <input> will support informal parameters.

...

If your component should render informal parameters, just inject the ComponentResources for your component and invoke the renderInformalParameters() method. See Supporting Informal Component Parameters for an example of how to do this.

...

Parameters are not simply variables; each parameter represents a connection, or binding, between a component and a property of its container. When using the prop: binding prefix, the component can force changes into a property of its container, just by assigning a value to its own instance variable.

Code Block
languagexml
<t:layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
    <p> Countdown:
        <t:count start="5" end="1" result="index">
          ${index} ...
        </t:count>
    </p>
</t:layout>

Because the Count component updates its result parameter (the result field), the index property of the containing component is updated. Inside the Count's body, we output the current value of the index property, using the expansion ${index}. The resulting output will look something like:

Code Block
languagexml
  <p> Countdown: 5 ... 4 ... 3 ... 2 ... 1 ... </p>

(Though the whitespace will be quite different.)

...

Inherited bindings are useful for complex components; they are often used when an inner component has a default value for a parameter, and the outer component wants to make it possible to override that default..

Code Block
languagexml
titleIndex.tml
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
  <body>
    <div t:type="layout" t:menuTitle="literal:The Title">
      ...
    </div>
  </body>
</html>
Code Block
languagexml
titleLayout.tml
<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">

	<div t:type="title" t:title="inherit:menuTitle"></div>

	<t:body />

</t:container>
Code Block
languagejava
titleTitle.java
package org.example.app.components;

import org.apache.tapestry5.annotations.Parameter;

public class Title {

	@Parameter
	private String title;

}

Computed Parameter Binding Defaults

...

Using this approach, the previous example may be rewritten as:

Code Block
languagejava
  @Parameter
  private String message;

  @Parameter(required=true)
  private int maxLength;

  @Inject
  private ComponentResources resources;

  @Inject
  private BindingSource bindingSource;

  Binding defaultMessage()
  {
    return bindingSource.newBinding("default value", resources, "basicMessage")

...

;
  }

  public String getBasicMessage()
  {
    return String.format("Maximum field length is %d.", maxLength);
  }

In this example, a property expression, "basicMessage", is used to access the message dynamically.

Alternately, the previous example may be written even more succinctly as:

Code Block
languagejava
  @Parameter
  private String message;

  @Parameter(required=true)
  private int maxLength;

  @Inject
  private ComponentResources resources;

  String defaultMessage()
  {
    return String.format("Maximum field length is %d.", maxLength);
  }

This form is more like using the "literal:" binding prefix, except that the literal value is computed by the defaultMessage() method.

...

Parameter Type Coercion

Main Article: Parameter Type Coercion Component Parameters

Tapestry includes a mechanism for coercing types automatically. Most often, this is used to convert literal strings into appropriate values, but in many cases, more complex conversions will occur. This mechanism is used for component parameters, such as when an outer component passes a literal string to an inner component that is expecting an integer.

You can easily contribute new coercions for your own purposes.

Parameter Names

...

In rare cases, you may want to take different behaviors based on whether a parameter is bound or not. This can be accomplished by querying the component's resources, which can be injected into the component using the @Inject annotation:

Code Block
languagejava
public class MyComponent
{
  @Parameter
  private int myParam;

  @Inject
  private ComponentResources resources;

  @BeginRender
  void setup()
  {
      if (resources.isBound("myParam"

...

))
      {
        . . .
      }
  }
}

The above sketch illustrates the approach. Because the parameter type is a primitive type, int, it is hard to distinguish between no binding, and binding explicitly to the value 0.

...

In Tapestry 5.1 and later, you may use the publishParameters attribute of the @Component annotation. List one or more parameters separated by commas: those parameters of the inner/embedded component become parameters of the outer component. You should not define a parameter field in the outer component.

Code Block
languagexml
titleContainerComponent.tml
<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<t:pageLink t:id="link">Page Link</t:pageLink>
</t:container>
Code Block
languagejava
titleContainerComponent.java
public class ContainerComponent{
    @Component(id="link", publishParameters="page")
    private PageLink link;
}
Code Block
languagexml
titleIndex.tml
<t:ContainerComponent t:id="Container" t:page="About" />

There are still cases where you want to use the "inherit:" binding prefix. For example, if you have several components that need to share a parameter, then you must do it the Tapestry 5.0 way: a true parameter on the outer component, and "inherit:" bindings on the embedded components. You can follow a similar pattern to rename a parameter in the outer component.