...
Rendering
...
Wiki Markup |
---|
{float:right|background=#eee}
{contentbylabel:title=Related Articles|showLabels=false|showSpace=false|space=@self|labels=request-processing,rendering}
{float} |
Rendering of components in Tapestry 5 is based on a state machine and a queue (instead of the tail recursion used in Tapestry 4). This breaks the rendering process up into tiny pieces that can easily be implemented or overridden. Don't worry, in practice, writing components requires a breathtakingly small amount of code.
Div |
---|
Rendering Phases
| ||||||||||
|
Rendering Phases
The The rendering of each component is divided into a number of phases, illustrated below.
Each of the orange phases (SetupRender, BeginRender, BeforeRenderBody, etc.) corresponds to an annotation you may place on one or more methods of your class. The annotation directs Tapestry to invoke your method as part of that phase.
...
All Render phase methods are optional; a default behavior is associated with each phase.
Annotation | Method Name | When Called |
---|---|---|
setupRender() | When initial setup actions, if any, are needed | |
beginRender() | When Tapestry is ready for the component's start tag, if any, to be rendered | |
beforeRenderTemplate() | Before Tapestry renders the component's template, if any | |
beforeRenderBody() | Before Tapestry renders the body of the component, if any | |
afterRenderBody() | After Tapestry renders the body of the component, if any, but before the rest of the component's template is rendered | |
afterRenderTemplate() | After Tapestry finishes rendering the component's template, if any | |
afterRender() | After Tapestry has finished rendering both the template and body of the component | |
cleanupRender() | When final cleanup actions, if any, are needed |
The large number of phases reflects the need for precise control of components from component mixins. Several of the phases exist almost exclusively for mixins.
...
Here's the source for a looping component that counts up or down between two values, renders its body a number of times, and stores the current index value in a parameter:
Code Block | ||||
---|---|---|---|---|
| ||||
package org.example.app.components;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.AfterRender;
import org.apache.tapestry5.annotations.SetupRender;
public class Count
{
@Parameter
private int start = 1;
@Parameter(required = true)
private int end;
@Parameter
private int value;
private boolean increment;
@SetupRender
void initializeValue()
{
value = start;
increment = start < end;
}
@AfterRender
boolean next()
{
if (increment)
{
int newValue = value + 1;
if (newValue <= end)
{
value = newValue;
return false;
}
}
else
{
int newValue = value - 1;
if (newValue >= end)
{
value = newValue;
return false;
}
}
return true;
}
}
|
...
What's really mind blowing is that the template and body of a component will often contain ... more components! That means that many different components will be in different phases of their own state machine.
Render Phases in Detail
Note |
---|
The SetupRender phase, like all render phases, occurs once for each rendering of the component. If the component is inside a looping component (Loop, Grid, etc.), then the SetupRender method will be called once for each iteration of the loop. |
Wiki Markup |
{float:right|background=#eee|width=50%} {note} The SetupRender phase, like all render phases, occurs once for each rendering of the component. If the component is inside a looping component ([Loop|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Loop.html], [Grid|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Grid.html], etc.), then the SetupRender method will be called once for _each_ iteration of the loop. {note} {float} |
SetupRender
The SetupRender phase (see @SetupRender) is where you can perform any one-time per-render setup for your component. This is a good place to read component parameters and use them to set temporary instance variables.
...
Using this mechanism, the earlier example can be rewritten as:
Code Block | ||||
---|---|---|---|---|
| ||||
package org.example.app.components;
import org.apache.tapestry5.annotations.Parameter;
public class Count
{
@Parameter
private int start = 1;
@Parameter(required = true)
private int end;
@Parameter
private int value;
private boolean increment;
void setupRender()
{
value = start;
increment = start < end;
}
boolean afterRender()
{
if (increment)
{
int newValue = value + 1;
if (newValue <= end)
{
value = newValue;
return false;
}
}
else
{
int newValue = value - 1;
if (newValue >= end)
{
value = newValue;
return false;
}
}
return true;
}
}
|
...
The following component returns a Renderable in the BeginRender phase and skips the BeforeRenderTemplate phase:
Code Block | ||
---|---|---|
| ||
public class OutputValueComponent
{
@Parameter
private String value;
Object beginRender()
{
return new Renderable()
{
public void render(MarkupWriter writer)
{
writer.write(value);
}
};
}
}
|
...
To turn on rendering comments only for a particular request, add the query parameter t:component-trace=true
to the URL:
Code Block |
---|
http://www.example.com/myapp/mypage?t:component-trace=true
|
Scrollbar |
---|