Renders the body of a Block component, which may be selected dynamically. The Block may be on the same page as the RenderBlock or on another page entirely.
Warning:The PageBeginRenderListener (and PageEndRenderListener ) event notications only go to the active page (the active page is the page that renders the response). It is possible to pass a Block from an entirely different page to a RenderBlock, but render listeners of both types on the non-active pages will not be notified.
See also: org.apache.tapestry.components.RenderBlock , Block
Name | Type | Required | Default | Description |
---|---|---|---|---|
block | Block | yes | The Block to render. |
Body: removed
Informal parameters: allowed
Reserved parameters: none
Informal parameters are allowed, but are not used by the RenderBlock component.
Instead, they are used to pass information to the
Block
itself. The Block's invoker property will be the
RenderBlock
that invokes it (in 3.0, this property was called "inserter", which is
maintained for backwards compatibility). The parameters of the RenderBlock are
available via the getParameter()
method of
Block
. This is most useful when the RenderBlock and Block are contained within
different components or even different pages.
This example shows a page with a custom TabPanel component. When a user selects a tab, TabPanel switches content. Each tab content is defined by a Block. The final result shows a tab view that highlights the currently selected tab:
First we'll show a page that makes use of the TabPanel component.
TabTest.html:
<html jwcid="@Shell" title="TabPanel Test"> <body> <span jwcid="@TabPanel" blockIds="ognl:{'berlin', 'rome', 'tokyo'}" selectColor="#FFFF00" unSelectColor="#CCFFFF" borderColor="#00CC33"/> <span jwcid="berlin@Block"> <h1>Berlin</h1> </span> <span jwcid="rome@Block"> <h1>Rome</h1> </span> <span jwcid="tokyo@Block"> <h1>Tokyo</h1> </span> </body> </html>
For simplicity, this example uses an engineered naming coincidence : the names of the Block components matches the localized message key used to obtain the title. In this case, the Blocks contain just a snippet of HTML ... but they could contain any valid markup, including components, links, forms, or other complex components. The use of OGNL makes it easy to assemble a list of strings, the component ids for the Blocks, and pass that list into the TabPanel component.
TabTest.properties:
berlin=Berlin rome=Rome tokyo=Tokyo
Most of the interesting parts, including the use of the RenderBlock component, occurs inside the TabPanel component specification and template.
TabPanel.html:
<table border="0" width="50%" cellspacing="0" cellpadding="0"> <tr> <td width="10"> </td> <td> <table border="0" cellspacing="0" cellpadding="5"> <tr> <span jwcid="loop"> <td jwcid="tab"> <a jwcid="link"> <span jwcid="@Insert" value="ognl:container.messages.getMessage(blockId)">Tab Title</span> </a> </td> <td width="1"></td> </span> </tr> </table> </td> <td width="10"> </td> </tr> <tr> <td jwcid="@Any" height="5" bgcolor="ognl:borderColor" colspan="3"> </td> </tr> <tr> <td jwcid="@Any" width="10" bgcolor="ognl:borderColor"> </td> <td align="center"> <span jwcid="@RenderBlock" block="ognl:selectedBlock">Page content goes here</span> </td> <td jwcid="@Any" width="10" bgcolor="ognl:borderColor"> </td> </tr> <tr> <td jwcid="@Any" height="5" bgcolor="ognl:borderColor" colspan="3"> </td> </tr> </table>
The key concepts shown here are:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE component-specification PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN" "http://tapestry.apache.org/dtd/Tapestry_4_0.dtd"> <component-specification class="com.example.components.TabPanel" allow-body="no" allow-informal-parameters="no"> <property name="selectedBlockId" persist="session"/> <parameter name="blockIds" required="yes"/> <parameter name="borderColor" required="yes"/> <parameter name="selectColor" default-value="#7D000D"/> <parameter name="unSelectColor" default-value="#C0C0C0"/> <component id="loop" type="Foreach"> <binding name="source" value="blockIds"/> <binding name="value" value="blockId"/> </component> <component id="tab" type="Any"> <binding name="bgcolor"> tabSelected ? selectColor : unSelectColor </binding> </component> <component id="link" type="DirectLink"> <binding name="listener" value="listener:doClick"/> <binding name="parameters" value="blockId"/> <binding name="disabled" value="tabSelected"/> </component> </component-specification>
package com.example.components; import org.apache.tapestry.BaseComponent; import org.apache.tapestry.components.Block; import java.util.List; public abstract class TabPanel extends BaseComponent { // Persistent public abstract String getSelectedBlockId(); public abstract void setSelectedBlockId(String id); public abstract List getBlockIds(); // Current block id within the loop public abstract String getBlockId(); public Block getSelectedBlock() { String selectedId = getSelectedBlockId(); if (selectedId == null) selectedId = (String) getBlockIds().get(0); return (Block) getContainer().getComponent(selectedId); } public boolean isTabSelected() { String selectedId = getSelectedBlockId(); if (selectedId == null) selectedId = (String) getBlockIds().get(0); return getBlockId().equals(selectedId); } public void doClick(String selectedId) { setSelectedBlockId(selectedId); } }
The only major trick here is that initially the persistent selectedBlockId property will be null, and we have to work around it by treating the first element in the blockIds parameter as the default selectedBlockId. The doClick() listener method is very simple; the blockId that was passed in the URL is obtained and used to update the selectedBlockId property, which was declared persistent in the specification.
Note that we don't store the Block instance as a persistent property ... components are not serializable and should never be stored as persistent properties. We store the id needed to locate the Block .