Tapestry 4.0 Notes

Sample page file

<?xml version="1.0"?>
<!DOCTYPE page-specification PUBLIC 
"-//Apache Software Foundation//Tapestry Specification 4.0//EN" 
"http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">

<page-specification class="com.foo.SomePage">
    
  <description>Page Description</description>
    
  <parameter name="title" property="titleParameter"/>

  <property name="error"/>

  <bean name="delegate" class="com.foo.ValidationDelegate"/>
    
  <bean name="postalCodeValidator" class="org.apache.tapestry.form.validator.Pattern">
    <set name="pattern">'[A-CEGHJ-NPR-TVWY]\\d[A-Z]\\s\\d[A-Z]\\d'</set>
    <set name="message" value="message:error.postal.code"/>
  </bean>
         
  <asset name="submit" path="context:/images/button-submit.gif"/>     
  <asset name="cancel" path="context:/images/button-cancel.gif"/>   
       
</page-specification >

Sample jwc file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE component-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">

<component-specification class="com.foo.SomePageComponent"
  allow-body="yes"
  allow-informal-parameters="yes">
    
  <description>Component Description</description>
    
  <parameter name="title" property="titleParameter"/>

  <property name="error"/>

  <bean name="delegate" class="com.foo.ValidationDelegate"/>
    
  <bean name="postalCodeValidator" class="org.apache.tapestry.form.validator.Pattern">
    <set name="pattern">'[A-CEGHJ-NPR-TVWY]\\d[A-Z]\\s\\d[A-Z]\\d'</set>
    <set name="message" value="message:error.postal.code"/>
  </bean>
         
  <asset name="submit" path="context:/images/button-submit.gif"/>     
  <asset name="cancel" path="context:/images/button-cancel.gif"/>   
       
</component-specification>

Component java class

...
  @Parameter(required = true)
  public abstract String getSomeVariable();
...

Goto a new page

cycle.activate( "PageName" );
getRequestCycle().activate( "PageName" );
Warning
A PageRedirectException cannot be used inside a pageBeginRender method.
throw new PageRedirectException( getRequestCycle().getPage("PageName" ) );
@InjectObject("engine-service:page")
public abstract IEngineService getPageService();

// ...

public ILink submitForm()
{
  // ...

  if( isInError() )
  {
    delegate.record( getInErrorMessage(), ValidationConstraint.CONSISTENCY );
    return null;
  }

  if( isFormError() )
  {
    delegate.record( (IFormComponent) getPage().getComponent( "userId" ), getFormErrorMessage() );
  }

  // Returning a link from a listener will force a Redirect-after-Post
  return getPageService().getLink( false, "PageName" );
}
Warning
If you have a listener attached to the form submit and have listeners on the buttons, a redirect in the button listeners will prevent the form submit listener from being called.

Set a variable on a new page and goto it

AgentEdit page = (AgentEdit) getRequestCycle().getPage( "AgentEdit" );
page.setAgentId( agentId );
getRequestCycle().activate( page );
  // ...

  @InjectObject("engine-service:external")
  public abstract IEngineService getExternalService();

  // ...

  Object[] parameters = new Object[] { "SomeValue" };
  return getExternalService().getLink( 
     false, new ExternalServiceParameter( "NextPage", parameters ) );
   // ...

  // ...

  public void activateExternalPage( Object[] arg0, IRequestCycle cycle )
  {
    String someValue= (String) arg0[ 0 ];
    // ...
  }
  // ...

Using annotations to get properties

@Message("text.someProperty")
public abstract String getSomePropertyMessage();

Validation: Simple required field

page file
<bean name="delegate" 
      class="org.apache.tapestry.valid.ValidationDelegate" 
      property="delegate"/>

...

<component id="name" type="TextField">
  <binding name="value" value="name"/>
  <binding name="validators" value="validators:required[%error.missing-name]"/>
</component>
properties file
error.missing-name=Missing name.
html file
<span key="label.name"/>
<input jwcid="name" size="35" maxlength="35" />
Warning
If you have a listener attached to the form submit and have listeners on the buttons, a redirect in the button listeners will prevent the form submit listener from being called.

Validation: Advanced validation

page file
<bean name="delegate" 
      class="org.apache.tapestry.valid.ValidationDelegate" 
      property="delegate"/>
        
<bean name="alphanumericValidator" 
      class="org.apache.tapestry.form.validator.Pattern">
  <set name="pattern">'[A-Z,a-z,0-9]*'</set>
  <set name="message" value="message:error.must-be-alphanumeric"/>
</bean>

...

<component id="name" type="TextField">
  <binding name="displayName" value="message:error.name"/>
  <binding name="value" value="name"/>
  <binding name="validators" 
           value="validators:required[%error.missing-name],
                  minLength=3[%error.name-too-short],
                  maxLength=10[%error.name-too-long],
                  $alphanumericValidator"/>
</component>
properties file
error.missing-name=Missing name.
error.name-too-short=Must be 3 characters.
error.name-too-long=Cannot be greater then 10 characters.
error.must-be-alphanumeric=Must be alphanumeric.
html file
<span key="label.name"/>
<input jwcid="name" size="35" maxlength="35" />

Validation: pre-rendered errors


...

@Override
public void pageEndRender( PageEvent event )
{
  if( displayErrorMessage() )
  {
    setError( "Some error message." );

    getValidationDelegate().record(
      (IFormComponent) getPage().getComponent( "someComponentId" ), SOME_ERROR_KEY );
}

...

Listeners

There are several different ways to use listeners.

As the part of a DirectLink, using either an 'ognl:listeners.' or 'listener:' notation:

<span jwcid="@DirectLink" listener="ognl:listeners.Logout">
<span jwcid="@DirectLink" listener="listener:Logout">

As the default form listener:

<form jwcid="@Form"
      stateful="false"
      delegate="ognl:beans.delegate"
      listener="listener:save">
...
  <input jwcid="@Submit" value="message:button.save"/>
  <input jwcid="@Submit" listener="listener:cancel" value="message:button.cancel"/>
</form>
If you use multiple parameters on a method, do not use an Object[]. Rather, specify them explicitly in the listener method signature.
<span jwcid="@DirectLink" 
      listener="listener:someListener"
      parameters="ognl:{ 'a', 'b', 'c' }">
click
</span>
public ILink someListener( String argA, String argB, String ArgC )
{
  ...
}

Commonly overriden methods

public abstract class SomePage extends BasePage
{
  ...
  public void pageBeginRender(PageEvent event) 
  {
    //Code to run when page starts.
  }
  ...
}
public abstract class SomeComponent extends BaseComponent
{
  ...
  public void prepareForRender( IRequestCycle cycle )
  {
    //Code to run when component starts.
  }
  ...
}

Protected Page

The page class (or it's base class) must implement PageValidateListener and the method pageValidate() setup to redirect (usually throw a PageRedirectException) to a login page if not authenticated.

public abstract class ProtectedBasePage extends BasePage implements PageValidateListener 
{
  ... 
  public void pageValidate( PageEvent event ) 
  {
     if ( !"password".equals( getPassword() ) ) 
     {
       throw new PageRedirectException("Home");
     }
  }
  ... 
}

If logic in html

Any logic in the html page must be replaced with entities. Furthermore, the ognl: is only required for the opening of the condition.

<span jwcid="@If" condition="ognl:firstBoolean &amp;&amp; secondBoolean == null">
  ...
</span>
<span jwcid="@Else">
  ...
</span>

Using ognl variables in javascript call

To mix an ognl expression in a javascript call, the expression must be part of a jwcid element and the expression itself must start with ognl.

<input jwcid="@Button"
       type="button"
       onclick="ognl:'SomeFunctionClass.someMethod(\'' + tapestryOgnlVariable+ '\')'"
       value="Cancel">Cancel</input>

Clearing a form using ognl variables in a javascript call

Tapestry will override any form id if there are multiple forms on a page, relying on Form0 is not safe.

Instead use ognl in the javascript to explicitly refer to the component id.

...
<form jwcid="FormComponentId@Form">
...
</form>
...
<a jwcid="@Any" 
   href="javascript:void(0)" 
   onClick="ognl:'resetForm(\'' + getComponent('FormComponentId').name + '\')'"/>
...

Date formatting

Using a property to format the display of a date.

...
  @Message("format.date")
  public abstract String getDateFormatProperty();
...
  private Format dateFormat;

  public Format getDateFormat()
  {
    if( dateFormat == null )
      dateFormat = new SimpleDateFormat( getDateFormatProperty() );
    return dateFormat;
  }
...
html file
...
<span jwcid="@Insert" 
      value="ognl:someDateValue"
      format="ognl:dateFormat" />
...
property file
...
format.date=MM/dd/yyyy
...

Persisting data

...
  @Persist
  public abstract String getFoo();

  public abstract void setFoo( String value );
...

Redirect after post

public abstract class SubmitPage extends SomeBasePage
{
...
  @InjectObject("engine-service:external")
  public abstract IEngineService getExternalService();
...
  public ILink someListenerMethod()
  {
    IValidationDelegate delegate = (IValidationDelegate) getBeans().getBean(
        "delegate" );

    //Bounce if the Required validator has errors.
    if( delegate.getHasErrors() )
    {
      return null;
    }
...
    Object[] parameters = new Object[] { SUCCESS_KEY };

    return getExternalService().getLink( false,
        new ExternalServiceParameter( "NextPage", parameters ) );
  }
...
public abstract class NextPage extends SomeBasePage implements IExternalPage
{
...
  public void activateExternalPage( Object[] parameters, IRequestCycle cycle )
  {
    setSuccess( getUiMessage( (String) parameters[ 0 ] ) );
  }
...
 return getPageService().getLink( false, "NextPage" );
...

Zebra stripes on a table

html file
 
<span jwcid="@For" 
      source="ognl:agents" 
      value="ognl:agent" 
      element="tr" 
      index="ognl:rowIndex"
      class='ognl:rowIndex%2==0?"r1":"r2"'>
page file
 
<property name="rowIndex" />

Using a Render Block with a If Else

<span jwcid="@If" condition="ognl:isAgentNumberInErrorFlag">
  <div class="error">
    <span jwcid="@RenderBlock" block="ognl:agentNumberBlock"/>
  </div>
</span>
<span jwcid="@Else">
  <span jwcid="@RenderBlock" block="ognl:agentNumberBlock"/>
</span>

<span jwcid="agentNumberBlock@Block">
<label jwcid="@FieldLabel" 
       field="component:agentNumber" 
       displayName="message:label.agent-number"/>
<input type="text" 
       size="9" 
       maxlength="9" 
       jwcid="agentNumber@LoyaltyTextField" 
       value="ognl:agentNumber"
       validators="validators:agentNumberValidator" />

</span>

Using properties

text.foo=Foo
<p class="someClass">
  <span jwcid="@Insert" value="message:text.foo" raw="true"/>
</p>

Credit and Thanks

Michael Prescott
Dave Park


Browse Space

- Pages
- Blog
- Labels
- Attachments
- Bookmarks
- Mail
- Advanced

Explore Confluence

- Popular Labels
- Notation Guide

Your Account

Log In

 

Other Features

Add Content