Making a component Layout with Tapestry 5 is really simple.

An example is given at: http://tapestry.apache.org/tapestry5/guide/layout.html in the official tapestry 5 documentation but I propose a more sophisticated component with content fallback, able for instance to override its left column content if needed.

We'll finish with something that will look like a bit like the Tiles Template system (Struts), but much much simpler than Tiles.

In the package components, create a Layout component and template

Layout.java :

   1 import org.apache.tapestry.annotations.Parameter;
   2 import org.apache.tapestry.ioc.annotations.Inject;
   3 import org.apache.tapestry.services.Request;
   4 
   5 /**
   6 * @author Michael Courcy
   7 *
   8 * This component aims to provide layout service for a page
   9 *
  10 */
  11 @IncludeStylesheet("context:layout.css")
  12 public class Layout {
  13 
  14         @Parameter
  15         private String title = "My Tapestry powered site";
  16         
  17         @Inject
  18         private Request request;
  19         
  20         public String getTitle() {
  21          return title;
  22         }
  23         
  24         public void setTitle(String title) {
  25          this.title = title;
  26         }
  27         
  28         public Request getRequest() {
  29          return request;
  30         }
  31         
  32         public void setRequest(Request request) {
  33          this.request = request;
  34         }
  35 }

Layout.tml

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>${title}</title>
</head>
<body>

 <table id="main">
        <tr>
         <td id="header" colspan="2">
          The header
         </td>
        </tr>
        <tr>
         <td id="left">
          Here come the left content
         </td>
         <td id="content">
          <t:body/>
         </td>
        </tr>
        <tr>
         <td id="footer" colspan="2">
          Tapestry powered Site
         </td>
        </tr>
 </table>

</body>
</html>

Then add this css file in the root context of your webapp.

layout.css

table#main {
width: 700px;
margin-left:auto;
margin-right:auto;
}

td#header {
height: 120x;
border: 1px solid blue;
padding: 10px;
margin: 10px;
}

td#footer {
height: 120x;
border: 1px solid blue;
padding: 10px;
margin: 10px;
}

td#left{
width: 200px;
border: 1px solid red;
padding: 10px;
margin: 10px;
}

td#content{
border: 1px solid red;
padding: 10px;
margin: 10px;
}

Let's try it! In the package page, create a page TestLayout.java which does ot do anything as its only purpose is to test the component.

   1 public class TestLayout {
   2 
   3 }

and in the root context of your webapp, create the template TestLayout.tml :

<t:layout title="literal:My first use of layout component" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
My content
</t:layout>

You should get this:

layout_first_step.png

Note that the title of the page is passed as a parameter.

But could we regard this solution as fulfilling our requirements?

Not really, because the content of the left column is now static and we're about 100% sure that for some pages we'll have to override it.

Let's change the component using Delegate, Block, Parameter and a component of our own : Left.

Left.java (in the components package)

   1 /**
   2 * @author Michael Courcy
   3 *
   4 * This component is just a content holder to fill the left column of the layout component
   5 *
   6 */
   7 public class Left {
   8 
   9 }

Really simple, isn't it? That's barely a container.

Now let's change Layout.tml.

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>${title}</title>
<link href="${request.contextPath}/layout.css" rel="stylesheet" type="text/css" />
</head>
<body>

 <table id="main">
        <tr>
         <td id="header" colspan="2">
          The header
         </td>
        </tr>
        <tr>
         <td id="left">
          <t:delegate to="leftContent" />
          <t:block>
           <div t:id="leftRegularContent">
            Here come the left regular content
           </div>
          </t:block>
         </td>
         <td id="content">
          <t:body/>
         </td>
        </tr>
        <tr>
         <td id="footer" colspan="2">
          Tapestry powered Site
         </td>
        </tr>
 </table>

</body>
</html>

What you have to focus on is the change done in the left column, the content of the component leftRegularContent will be a "content fallback".

You have to change Layout.java as well

   1 package org.apache.tutorial.tapestrySpringHibernate.components;
   2 
   3 import org.apache.tapestry.Block;
   4 import org.apache.tapestry.annotations.Component;
   5 import org.apache.tapestry.annotations.Parameter;
   6 import org.apache.tapestry.ioc.annotations.Inject;
   7 import org.apache.tapestry.services.Request;
   8 
   9 /**
  10 * @author Michael Courcy
  11 *
  12 * This component aims to create a layout around the main content
  13 * You can optionnaly defines left content that overrides the regular left
  14 * content if needed through the <t:parameter name="left">some overiding left content</t:parameter>
  15 *
  16 */
  17 public class Layout {
  18 
  19         @Parameter
  20         private String title = "My Tapestry powered site";
  21         
  22         @Parameter
  23         private Block left;
  24         
  25         @Component
  26         private Left leftRegularContent;
  27         
  28         @Inject
  29         private Request request;
  30         
  31         /**
  32          * This method check if the left parameter has been set by the user
  33          * if not the regular content is shown otherwise the content of this parameter
  34          *
  35          * @return the component we want to display
  36          */
  37         public Object getLeftContent(){
  38          return left==null ?  leftRegularContent : left;
  39         }
  40         
  41         public String getTitle() {
  42          return title;
  43         }
  44         
  45         public void setTitle(String title) {
  46          this.title = title;
  47         }
  48         
  49         public Request getRequest() {
  50          return request;
  51         }
  52         
  53         public void setRequest(Request request) {
  54          this.request = request;
  55         }
  56 }

Et voila !! Without defining a left parameter :

   1 <t:layout title="literal:My first use of layout component" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
   2 My content
   3 </t:layout>

you get this:

layout_second_step_nol_overriding_left.png

With a left parameter defined :

<t:layout title="literal:My first use of layout component" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
My content
<t:parameter name="left">
   Other left content
   </t:parameter>
</t:layout>

You get this:

layout_second_step_overriding_left.png

(originally posted on Michael Courcy's blog - the images only work if you right click and view image, if anyone can fix this or can host the images where they'll work inline - please do so )

NOTE: Inline images have now been fixed (11/23/2008)

Tapestry5Layoutcomponent (last edited 2010-03-31 22:03:36 by LeonardLu)