tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Tapestry Wiki] Update of "Tapestry5HowToCreateTabPanel" by ErikVullings
Date Mon, 11 Jun 2007 11:13:44 GMT
Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for change notification.

The following page has been changed by ErikVullings:

The comment on the change is:
Attribution goes to Kris Marinkovic, who explained the process to me

New page:
I wanted to create a tab panel in T5, and Kris Marinkovic was so nice to explain it to me
in his email on June 11, 2007 (in the tapestry users email list). It's actually quite simple
to do, and I've learned some new concepts from it too, so let's get to it.

Assume you have created a Tab component (e.g. declared in org.example.myapp.components). I'll
keep it simple, and this component's Tab.html isn't there (so there is no template), and the
Tab.java only contains a default setter to display a message.
package org.example.myapp.components;

import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.annotations.BeginRender;

public class Tab {
	private String message="Bonjour from HelloWorld component.";
	void renderMessage(MarkupWriter writer) {

	public void setMessage(String message) {
		this.message = message;

Now that you have a component to display the tab panel's content, you need a way to select
it. Let's assume your Start page needs to contain the tab panel. To make it more interesting,
I've used Yahoo's YUI library to create a header/footer/secondary/main page layout. So here
is your Start.html template file:
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<title>Start Page</title>
<!-- Load all necesary javascript files and style sheets -->
<link rel="stylesheet" href="css/reset-fonts-grids.css" type="text/css"></link>
<link rel="stylesheet" href="css/styles.css" type="text/css"></link>
<div id="doc" class="yui-t2">
<div id="hd">
<p align="center">
Header placeholder
<p align="right">
	<t:actionlink t:id="tab1_link" title="My first tab">Tab1</t:actionlink>
	<t:actionlink t:id="tab2_link" title="My second tab">Tab2</t:actionlink>
	<t:actionlink t:id="tab3_link" title="My third tab">Tab3</t:actionlink>

<div id="secondary" class="yui-b">
Menu placeholder

<div id="yui-main">
	<div class="yui-b">
		<div id="mainContent">
			<t:delegate to="selectedTab"/>
				<div t:id="tab1"/>
				<div t:id="tab2"/>
				<div t:id="tab3"/>

<div id="ft">
<p align="center">Placeholder for footer</p>


Pay special attention to the {{{<t:actionlink t:id="tab1_link" ...}}}, which declares the
tabs. Furthermore, the {{{<t:delegate to="selectedTab"/>}}} instruction above is a placeholder
for your new component. Since a delegate doesn't do any rendering (i.e. no output is generated),
it requests the Start.java file to return a component which can render itself. This component
can have the name tab1, tab2 or tab3, and replaces the respective {{{<div t:id="tab1"/>}}}
in the {{{<t:block>}}} statement. 

To complete the story, I'll show you the Start.java file:
package org.example.myapp.pages;

import org.apache.tapestry.annotations.Component;
import org.apache.tapestry.annotations.Persist;

import org.example.myapp.components.Tab;

public class Layout {
	// All components need to be declared (otherwise, your page will generate an error, since
the <t:block> block
	// expects them and names them.
	@Component private Tab tab1;
	@Component private Tab tab2;
	@Component private Tab tab3;

	// Due to the page redirect, you need to persist the value briefly
	private int selectedComponent;

	// These are the event methods that are generated by clicking on the Tab. Due to the specific
	// syntax, onActionFromIDNAME, there is no need for the @OnEvent annotation, although that
would work too.
	public void onActionFromTab1_link() {	selectedComponent = 1; }
	public void onActionFromTab2_link() {	selectedComponent = 2; }
	public void onActionFromTab3_link() {	selectedComponent = 3; }

	// Returns the selected tab, which will take the place of the corresponding <div t:id="tabXXX"/>
	public Object getSelectedTab() {
		switch (selectedComponent) {
		case 1:
			return tab1;
		case 2:
			return tab2;
		case 3:
			return tab3;
			return tab1;

That should do the trick.

To recapitulate, the flow of events is as follows:
 1. Initially, the Start page is requested to render. The {{{<t:delegate...}}} will request
the tab object to display
 1. Start.java contains a method, getSelectedTab(), which is invoked, and by default returns
the component called tab1. )Since all components are the same, I've set the message to tab1
as well to distinguish them).
 1. Since the component tab1 is returned, it takes the place in the {{{<t:block...}}} statement
 1. When the user clicks on tab2, Tab2_Link is invoked, which calls onActionFromTab2_link().
The only thing this does is to set the selectedComponent to 2. '''(Question: would it be possible
to have an onActionFromTab(int selectedComponent) method instead?)'''
 1. The page is re-rendered, but since the selectedComponent is 'flashed' to persist, during
the next rendering, its value is still 2
 1. We now return to the start, but tab2 is returned, and therefore the message will be "tab2".

To unsubscribe, e-mail: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org

View raw message