Wiki Markup |
---|
{float:right|background=#eee}
{contentbylabel:title=Related Articles|showLabels=false|showSpace=false|space=@self|labels=expressions,component-classes,component-templates,parameters}
{float} |
Component Parameters
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.
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 |
---|
|
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<t:pagelink page="Index">Go Home</t:pagelink>
</html>
|
...
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 |
---|
|
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 component above can be referenced in another component or page template, and its parameters bound:
Code Block |
---|
|
<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>
|
...
For example, the following template code:
Code Block |
---|
|
<ul>
<li t:type="loop" source="1..10" value="index">${index}</li>
</ul>
|
and the following Java code:
Code Block |
---|
|
@Property
private int index;
|
... could be rewritten as just:
Code Block |
---|
|
<ul>
<li t:type="loop" source="1..10" value="var:index">${var:index}</li>
</ul>
|
...
Assets bindings are used to specify assets Assets, 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 |
---|
|
<img src="${context:images/icon.png}"/>
|
...
Parameters that are required must be bound. A runtime exception occurs if a component has unbound required parameters.
Code Block |
---|
|
public class Component{
@Parameter(required = true)
private String parameter;
} |
...
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 |
---|
|
@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);
}
|
...
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 |
---|
language | xml |
---|
title | This is right | xml |
---|
|
<t:textfield t:id="color" value="color"/>
|
|
Column |
---|
Code Block |
---|
language | xml |
---|
title | This is wrongxml |
---|
|
<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 |
---|
language | xml |
---|
title | This is right | xml |
---|
|
<img src="${context:images/banner.png}"/>
|
|
Column |
---|
Code Block |
---|
language | xml |
---|
title | This is wrongxml |
---|
|
<img src="context:images/banner.png"/>
|
|
|
...
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 |
---|
|
<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 |
---|
|
<p> Countdown: 5 ... 4 ... 3 ... 2 ... 1 ... </p>
|
...
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 |
---|
language | xml |
---|
title | Index.tml | xml |
---|
|
<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 |
---|
language | xml |
---|
title | Layout.tmlxml |
---|
|
<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 |
---|
language | java |
---|
title | Title.java | java |
---|
|
package org.example.app.components;
import org.apache.tapestry5.annotations.Parameter;
public class Title {
@Parameter
private String title;
}
|
...
Using this approach, the previous example may be rewritten as:
Code Block |
---|
|
@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);
}
|
...
Alternately, the previous example may be written even more succinctly as:
Code Block |
---|
|
@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);
}
|
...
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 |
---|
|
public class MyComponent
{
@Parameter
private int myParam;
@Inject
private ComponentResources resources;
@BeginRender
void setup()
{
if (resources.isBound("myParam"))
{
. . .
}
}
}
|
...
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 |
---|
language | xml |
---|
title | ContainerComponent.tml | xml |
---|
|
<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 |
---|
language | java |
---|
title | ContainerComponent.java |
---|
|
public class ContainerComponent{
@Component(id="link", publishParameters="page")
private PageLink link;
}
|
Code Block |
---|
language | xml |
---|
title | Index.tmlxml |
---|
|
<t:ContainerComponent t:id="Container" t:page="About" />
|
...