Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: scrollbar
Div

Component Templates

{} {info:title=Related Articles} * [Templating and Markup FAQ|Templating and Markup] * [Component Classes] {info} {float}
Wiki Markup
style
float:right
; margin: 1em
titleRelated Articles
classaui-label
Content by Label
showLabelsfalse
showSpacefalse
titleRelated Articles
cqllabel in ("component-templates","components","rendering","response") and space = currentSpace()

Under Tapestry, a component template is a file that contains the markup for a Under Tapestry, a component template is the file associated with a page or component class that contains the markup for that page or component.

Component templates are well formed XML documents. That means that every open tag must have a matching close tag, every attribute must be quoted, and so forth.

...

Note: At runtime, Tapestry parses the documents and only checks for wellformedness. Even when the document has a DTD or schema, there are no validity checks.

For the most part, these templates are standard (X) HTML/XHTML; Tapestry extensions to ordinary markup are provided in the form of a Tapestry XML namespace .(xmlns):

Code Block
languagexml
titleA template for a page
<html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
    <h1>Bonjour from HelloWorld component.</h1>
</html>

We'll cover the specific content of templates shortly, but first a few details about connecting a component to its template.

Template Location

Component templates are stored with the component class file. The files have A component template shares the same name as its corresponding class file, but with a ".tml" extension ending (i.e., _T_apestry _M_arkup _L_anguage), and are is stored in the same package as the corresponding component class.

Under a typical Maven directory structure, the Java class and template files for a component might be:

Java class:

src/main/java/org/example/myapp/components/MyComponent.java

...

Template:

src/main/resources/org/example/myapp/components/MyComponent.tml

...

Likewise, the Java class and template files for a page might be:

Java class:

src/main/java/org/example/myapp/pages/MyPage.java

...

Template:

src/main/resources/org/example/myapp/pages/MyPage.tml

...

The template and the compiled class will be packaged together in the WEB-INF/classes folder of the application WAR.

For pages (but not other components), a second location will be searched: in the web application context. The location is based on the logical name of the page, in the previous example, the template would be MyPage.tml in the root folder of the web application.

...

Warning

Allowing pages to store their template in the web context is a feature that may go away at some point. It was included as a way for HTML designers to edit template directly and live preview the template directly, without executing the Tapestry application. This comes with a large number of limitations and leads to a false sense of security that a template that previews correctly will render properly (this is not always the case).

In certain cases, Tapestry will simplify the the logical name of a page. For example, the page class org.example.pages.address.CreateAddress will be given a logical name of "address/Create" (the redundant "Address" is removed as a suffix). However, this only affects how the page is referenced in URLs; the template file will still be CreateAddress.tml, whether on the classpath, or as address/CreateAddress.tml (in the web context).

Note

Tapestry actually creates multiple names for the name page: address/Create and address/CreateAddress are both synonymous. You can user either in Java code that refers to a page by name, or as the page parameter of a PageLink.

Template Localization

Main Article: Localization

Templates are in much the same way as individual files of a component's message catalog: the effective locale is inserted into the name of the file. Thus a German users will see the content generated from MyPage_de.tml and French users will see content generated from MyPage_fr.tml. When no specific localization is available, the default location (MyPage.tml) is used.

Warning

It is necessary to enable support for a locale before Tapestry will attempt to localize to that locale. This requires configuration in your application module; if you are using the Tapestry Quickstart archetype, only locale "en" will be enabled by default.

Template Doctypes

As mentioned above, component templates are well-formed XML documents. This means that if you want to use any HTML entities (such as \& \  < > ©), you must use an HTML or XHTML doctype in your template. If you choose to use (X)HTML doctypes in your templates, they will be passed on to the client in the resultant (X)HTML. Note that if your pages are composed of multiple components, each with a template, and each template contains a doctype declaration, only the first doctype encountered by the template parser will be passed on to the client.

It should also be noted that even though XHTML DTDs are valid XML DTDs, HTML DTDs aren't valid XML DTDs. This means that HTML doctypes cannot be used by XML parsers. Tapestry works around this limitation internally by using XHTML DTDs to parse templates that use HTML DTDs. This internal mapping is possible because XHTML 1.0 is nothing more than "a reformulation of the three HTML 4 document types as applications of XML 1.0," as per the W3C. Don't worry though – the original HTML 4 doctype will still be emitted to the client!

The following doctypes are the most common (X)HTML doctypes:

Template Localization

Main Article: Localization

Templates are handled in much the same way as individual files of a component's message catalog: the effective locale is inserted into the name of the file. Thus a German users will see the content generated from MyPage_de.tml and French users will see content generated from MyPage_fr.tml. When no specific localization is available, the default location (MyPage.tml) is used.

Info

It is necessary to enable support for a locale

before Tapestry will attempt to localize to that locale. This requires configuration in your application module (usually AppModule.java); if you are using the Tapestry Quickstart archetype, only locale "en" will be enabled by default.

Anchor
doctypes
doctypes

Template Doctypes

As mentioned above, component templates are well-formed XML documents. This means that if you want to use any Named HTML entities (such as &amp; &lt; &gt; &copy;), you must use an HTML or XHTML doctype in your template (starting in 5.3, this is more-or-less automatic, see notes below). If you choose to use (X)HTML doctypes in your templates, they will be passed on to the client in the resultant (X)HTML. Note that if your pages are composed of multiple components, each with a template, and each template contains a doctype declaration, only the first doctype encountered by the template parser will be passed on to the client.

It should also be noted that even though XHTML DTDs are valid XML DTDs, HTML DTDs aren't. This means that HTML doctypes cannot be used by XML parsers. Tapestry works around this limitation internally by using XHTML DTDs to parse templates that use HTML DTDs. This internal mapping is possible because XHTML 1.0 is nothing more than "a reformulation of the three HTML 4 document types as applications of XML 1.0," as per the W3C. Don't worry though – the original HTML 4 doctype will still be emitted to the client!

The following are the most common (X)HTML doctypes:

Code Block
xml
xml
<!DOCTYPE html>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1
Code Block
xmlxml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

Tapestry Namespace

Component templates should include the Tapestry namespace, defining it in the root element of the template.

The first one is for HTML5 and is recommended for Tapestry 5.2.5 and later. In versions prior to Tapestry 5.2.5, Tapestry didn't support the HTML5 doctype directly (but see the comments at TAP5-1040 for a work-around).

Since
since5.3
Tapestry 5.3 introduced two significant improvements to template Doctypes. A template without a is parsed as if it had the HTML Doctype ({{}}). In fact, Tapestry creates an in-memory copy of the template that includes the doctype. A template with the HTML Doctype ({{}}) is parsed as if it had the XHTML transitional Doctype. In fact, Tapestry creates an in-memory copy of the template that replaces the line. This applies as well to a template without any Doctype, in which case the XHTML transitional Doctype is inserted at the top. In either case, this means you can use arbitrary HTML entities, such as {{&copy;}} or {{&nbsp;}} without seeing the XML parsing errors that would occur in earlier releases.

The Tapestry Namespace

Component templates should include the Tapestry namespace, defining it in the root element of the template.

Code Block
languagexml
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.
Code Block
xmlxml

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
    <head>
        <title>Hello World Page</title>
    </head>
    <body>
        <h1>Hello World</h1>
    </body>
</html>

...

For backwards compatibility, you may continue to use the old namespace URIURIs: http://tapestry.apache.org/schema/tapestry_5_0_0.xsd. However or http://tapestry.apache.org/schema/tapestry_5_1_0.xsd or  http://tapestry.apache.org/schema/tapestry_5_3.xsd

 

 However, the following elements added, as part of Tapestry 5.1, will not work with the 5_0_0.xsd:

  • The <t:remove> Element
  • <t:content>
  • <t:extension-point>
  • <t:extend>
  • <t:replace>

The 5_3.xsd fixes some minor bugs in the 5_1_0.xsd, but is functionally equivalent; 5_3.xsd and 5_4.xsd are identical.

Tapestry Elements

Tapestry elements are elements defined using the Tapestry namespace prefix (usually "t:").

All other elements in your templates should be in the default namespace, with no prefix (with the possible exception of any Library Namespaces (described below).

There are a certain number of Tapestry elements, listed below, that act as template directives; beyond that, any element in the Tapestry namespace will be a Tapestry component.

The <t:body> Element

In many cases, a component is designed to integrate have its template with its container's templateintegrate with, or "wrap around", the containing component.

The <t:body> element is used to identify where, within a component's template, its body (from the container's template) is to be rendered.

...

The following example is a Layout component, that which adds basic HTML elements around the page-specific content:

Code Block
xml
languagexml

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_03.xsd">
    <head>
        <title>My Tapestry Application</title>
    </head>
    <body>
        <t:body/>
    </body>
</html>

That "<t:body/>" element marks where the containing page's content will be inserted. A page would then use this component as follow:

Code Block
xml
languagexml

<t:layout<html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_03.xsd">

  My Page Specific Content

</t:layout>
Note
In this example, t:layout creates a Layout component (more on this shortly).
 Content

</html>

When the page renders, the page's template and the Layout component's template are merged together:

Code Block
xml
languagexml

<html>
  <head>
    <title>My Tapestry Application</title>
  </head>
  <body>
    My Page Specific Content
  </body>
</html>
Noteinfo

Tapestry 4 users will recognize the <t:body> element as a replacement for the RenderBody component.

The <t:container> Element

A <t:container> element contains markup without being considered part of the template. This is useful for components that render several top level tags, for example, a component that renders several columns within a table row:

Code Block
xml
languagexml

<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_03.xsd">
  <td>${label}</td>
  <td>${value}</td>
</t:container>

...

Without the <t:container> element, there would be no way to create a valid XML document as the template, because XML documents must always have a single root element.

Anchor
nameblock

The <t:block> Element

A <t:block> is a container of a portion of the component template. A block does not normally render; any component or contents you put inside a block will not ordinarily be rendered. However, by injecting the block you have precise control over when and if the content renders.

A block may be anonymous, or it may have an id (specified with the id attribute). Non-anonymous blocks Only blocks with an id may be injected into the component.

Warning

A <t:block> must be in the Tapestry namespace, but the id attribute should not be. This is different from components in the template, where the t:id attribute that defines the component id must be in the Tapestry namespace.

Ids must be valid Java identifiers: start with a letter, and contain only letters, numbers and underscores.

...

only letters, numbers and underscores.

The <t:parameter> Element

Note

This element was deprecated starting in Tapestry 5.1 and removed in 5.3. Use parameter namespaces (below) instead.

A <parameter> element is a special kind of block. It is placed inside the body of an embedded component. The block defined by the <parameter> is passed to the component. <parameter> includes a mandatory name attribute to identify which parameter of the component to bind.Example

The <t:

...


<t:if test="loggedIn">
  Hello, ${userName}!
  <t:parameter name="else">
  Click <a t:type="actionlink" t:id="login">here</a> to log in.
  </t:parameter>
</t:if>

content> Element

<t:content> marks a portion of the template as the actual template content; any markup outside the <t:content> element is ignored. This is useful for eliminating portions of the template that exist to support WYSIWYG preview of the template.

<t:content> elements may not nest.

Support for the <t:content> element was adding in Tapestry release 5.1. You must use the http://tapestry.apache.org/schema/tapestry_5_4.xsd or (or ...5_3 or ...5_1_0.xsd) namespace URI for content to be recognized (otherwise you will see an error about a missing "content" component).

<t:remove>

Warning

The parameter element has been deprecated (but is still fully supported, for backwards compatibility). The parameter namespace approach is more concise and readable.

...

Marks a portion of the template for removal; it is as the actual template content; any markup outside the <t:content> element is ignored. This is useful for eliminating portions of the template that exist to support WYSIWYG preview of the template.<t:content> elements may not nestif the remove element and everything inside it simply was not part of the template. This is used as a kind of server-side only comment (normal HTML/XML comments are included in a page render response), or to temporarily eliminate a portion of the template. As far as Tapestry is concerned, the contents of the <remove> element do not exist (including validating consistency between components defined or injected in the Java class and the template).

Support for the <t:content> remove> element was adding added in Tapestry release 5.1. You must use the http://tapestry.apache.org/schema/tapestry_5_4.xsd or (or ...5_3 or ...5_1_0.xsd) namespace URI for content remove to be recognized (otherwise you will see an error about a missing "contentremove" component).

<t:remove>

Marks a portion of the template for removal; it is as if the remove element and everything inside it simply was not part of the template. This is used as a kind of server-side only comment (normal HTML/XML comments are included in a page render response), or to temporarily eliminate a portion of the template. As far as Tapestry is concerned, the contents of the <remove> element do not exist (including validating consistency between components defined or injected in the Java class and the template).

Support for the <t:remove> element was adding in Tapestry release 5.1. You must use the http://tapestry.apache.org/schema/tapestry_5_1_0.xsd namespace URI for remove to be recognized (otherwise you will see an error about a missing "remove" component).

Expansions

Another option when rendering output is the use of expansions. Expansions are special strings that may be embedded in template bodies, and borrow some syntax from the Ant build tool.

...


  Welcome, ${userId}!

Here, ${userId} is the expansion. In this example, the userId property of the component is extracted, converted to a string, and streamed into the output.

Expansions are allowed inside text, and inside attributes of ordinary elements, and component elements. For example:

...


  <img src="${request.contextPath}/images/catalog/product_${productId}.png"/>

Anchor
Expansions
Expansions

Expansions

Another option when rendering output is the use of expansions. Expansions are special strings that may be embedded in template bodies, and borrow some syntax from the Ant build tool.

Code Block
languagexml
  Welcome, ${userId}!

Here, ${userId} is the expansion. In this example, the userId property of the component is extracted, converted to a string, and streamed into the output.

Expansions are allowed inside text, and inside attributes of ordinary elements, and component elements. For example:

Code Block
languagexml
  <img src="${request.contextPath}/images/catalog/product_${productId}.png"/>

In this hypothetical example, the component class is providing a request property and a productId property, and these are being used inside the template to assemble the src attribute of the <img> element. This is component-like behavior without actual components.

Under the covers, expansions are the same as parameter bindings. The default binding prefix for expansions is "prop:" (that is, the name of a property or a property expression), but other binding prefixes are useful, especially "message:" (to access a localized message from the component's message catalog).

Warning

Do not use expansions in component parameters if the parameter's default or explicit binding prefix is "prop:" or "var:". Expansions convert the value to an immutable string, resulting in a runtime exception if the component tries to update the value. Even for read-only parameters, expansions are not as desirable, since they always convert to a string, and from there to the parameter's declared type.

Info

Tapestry 4 users will note that expansions are a concise, easy replacement for the Insert component, and for the <span key="..."> directive.

Note that expansions escape any HTML reserved characters. Specifically, any less-than (<), greater than (>) and ampersand (&) are replaced with &lt;, &gt; and &amp; respectively. That is usually what you want. However, if your property contains HTML that you want rendered as raw markup, you can use the OutputRaw component instead, like this: <t:OutputRaw value="someContent"/> where someContent is a property containing HTML markup.

Caution: if the content comes from an untrusted source (like a public user), be sure to filter it before providing it to OutputRaw. Otherwise you've got a potential cross-site scripting vulnerability.

Embedded Components

In this hypothetical example, the component class is providing a request property and a productId property, and these are being used inside the template to assemble the src attribute of the <img> element. This is component-like behavior without actual components.

Under the covers, expansions are the same as parameter bindings. The default binding prefix for expansions is "prop:" (that is, the name of a property or a property expression), but other binding prefixes are useful, especially "message:" (to access a localized message from the component's message catalog).

Note

Tapestry 4 users will note that expansions are a concise, easy replacement for the Insert component, and for the <span key="..."> directive.

...

An embedded component is identified within the template as an element in the t: namespace. Example:

Code Block
xml
languagexml

  You have ${cartItems.size()} items in your cart.
  <t:actionlink t:id="clear">Remove All</t:actionlink>.

The element name, "actionlink" is used to select the type of component, ActionLink.

Noteinfo

As elsewhere, Tapestry is insensitive to case when mapping from a component type to a component class.

Embedded components may have two Tapestry-specific parameters:

  • id: A unique id for the component (within its container).
  • mixins: An optional comma separated list of mixins for the the component.

...

If the id attribute is omitted, Tapestry will assign a unique id for the element.

Warningnote

Non-trivial components should always be assigned a specific id, rather than letting Tapestry do it. You'll end up with shorter, more readable URLs and code that's easier to debug, because it will be more obvious how the request URL maps to your pages and components. This is even more strongly encourages encouraged for form control components, where the component id will usually be the same as the query parameter that stores the value provided by the end user.

...

The open and close tags of a Tapestry component element define the body of the component. It is quite common for additional components to be enclosed in the body of another component:

Code Block
xml
languagexml

<t:form>
  <t:errors/>
  <t:label for="userId"/>
  <t:textfield t:id="userId"/>
  <br/>
  <t:tablelabel for="password"/>
  <t:passwordfield t:id="password"/>
  <br/>
  <input type="submit" value="Login"/>
</t:form>

...

It is possible to place Tapestry components in sub-packages. For example, your application may have a package org.example.myapp.components.ajax.Dialog. This component's normal type name is "ajax/dialog" (because it is in the ajax subfoldersub-folder). This name is problematic, as it is not valid to define an XML element with an element name <t:ajax/dialog>. Instead, just replace the slashes with periods: <t:ajax.dialog>. Library namespaces (described in the next section) are a preferred way of handling components in sub-folders.

Noteinfo

When using a component library, the library will map its components to a virtual subfoldersub-folder of the application. The same naming mechanism works whether its is a real sub-folder or a component library sub-folder.

Anchor
LibraryNamespaces
LibraryNamespaces

Library Namespaces

If you are using many components from a common Tapestry component library, you can use a special namespace to simplify references to those components.

...

Borrowing from the above example, all of the following are equivalent:

Code Block
xml
languagexml

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_03.xsd" xmlns:a="tapestry-library:ajax">

  <t:ajax.dialog/>

  <span t:type="ajax/dialog"/>

  <a:dialog/>

  . . .

...

A favorite feature of Tapestry 4 was is invisible instrumentation, the ability to mark ordinary HTML elements as components. Invisible instrumentation leads to more concise templates that are also more readable.

For Tapestry 5, you make use of Invisible instrumentation involves using namespaced id or type attributes to mark an arbitrary ordinary (X)HTML element as a component, for example:. For example:

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

The t:type attribute above marks the span element as a component of type Count. When rendered, the span element will be replaced by the output of the Count component.

The id, type and mixins attributes must be placed in the Tapestry namespace (almost always as t:id, t:type, and mixins attributes must be placed in the Tapestry namespacet:mixins). Any additional attributes may be in either the Tapestry namespace or in the default namespace. Placing an attribute in the Tapestry namespace is useful when the attribute is not defined for the element being instrumented.

A An invisibly-instrumented component must still have a type, either identified in one of two ways:

  • via the t:type attribute in the containing template, as in the above example, or

...

  • within the

...

  • containing component's Java class using the @Component annotation (and using the t:id attribute on the

...

  • element in the template). The Component annotation is attached to a field; the type of the component is determined by either the type of the field or the type attribute of the Component annotation.

In most cases, it is merely an aesthetic choice between normal embedded components, and embedded components via whether to use invisible instrumentation . In a few instances, such as the Loop component, in your templates. However, in a very few cases the behavior of the component is influenced by your choice. The For example, when your template includes the Loop component , when included using the invisible instrumentation approach, will render the original tag (and any its informal parameters, around its body) will render repeatedly around the body of the component. Thus, for example:

Code Block
xml
languagexml

  <table>
    <tr t:type="loop" source="items" value="item" class="prop:rowClass">
      <td>${item.id}</td>
      <td>${item.name}</td>
      <td>${item.quantity}</td>
    </tr>
  </tabel>

Here, the loop component "merges into" the <tr> element. It will render out a <tr> for each item object in the items list in the items list, with each <tr> including three <td> elements. It will also write a dynamic "class" attribute into each <tr>.

Anchor
parameter-namespaces

...

parameter-namespaces

Parameter Namespaces

Main Article: Component Parameters

Parameter namespaces are a new feature (introduced in Tapestry 5.1. They ) are a more concise way of passing parameter blocks to components.

You must define a special namespace, usually given with the prefix "p":

Code Block
xml
languagexml

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_03.xsd" xmlns:p="tapestry:parameter">
  . . .

With the "tapestry:parameter" namespace defined, you can pass block using the "p:" prefix and an element name that matches the parameter name:

Code Block
xml
languagexml

<t:if test="loggedIn">
  Hello, ${userName}!
  <p:else>
    Click <a t:type="actionlink" t:id="login">here</a> to log in.
  </p:else>
</t:if>

This example passes a block of the template (containing the ActionLink component and some text) to the If component as parameter else. In the If component's reference page you'll see that else is parameter of type Block.

Name-spaced parameter elements are not allowed to have any attributes. The element name itself is used to identify the parameter of the component to bind.

...

This approach has certain efficiency advantages on both the server (less processing to render the page) and on the client (fewer characters to parse). Tools such as FireBug Firefox Developer Tools and Chrome Developer Tools are useful for allowing you to view the rendered HTML on the client properly.

...

The xml: namespace prefix is built into all XML documents, there is no special configuration (as there is with the Tapestry namespace).

For example:

Code Block
xml
languagexml

  <ul class="navmenu" xml:space="preserve">
    <li t:type="loop" t:source="pages" t:value="var:page">
      <t:pagelink page="var:page">${var:page}</t:pagelink>
    </li>
  </ul>

This will preserve the whitespace between the <ul> and <li> elements, and between the (rendered) <li> elements and the nested <a> elements. For example, the output may look something like:

Code Block
xml
languagexml

  <ul>
    <li>
      <a href="showcart>ShowCart</a>
    </li>
    <li>
      <a href="viewaccount">ViewAccount</a>
    </li>
  </ul>

With normal whitespace compression, you would see the following rendered output:

Code Block
xml
languagexml

  <ul><li><a href="showcart">ShowCart</a></li><li><a href="viewaccount">ViewAccount</li></ul>

...

Marks a point in a template that may be replaced. A unique id (case insensitive) is used in the template and its sub-templates to link extension points to possible overrides.

Code Block
xml
languagexml

  <t:extension-point id="title">
    <h1>${defaultTitle}</h1>
  </t:extension-point>

...

Replaces an extension point from a parent template. <t:replace> may only appear as the immediate child of a root <t:extend> element.

Code Block
xml
languagexml

<t:extend xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_03.xsd">
  <t:replace id="title">
    <h1><img src="${context:images/icon.jpg}"/>
    Customer Service</h1>
  </t:replace>
</t:extend>

Scrollbar