Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Fixed unbalanced {code} tag, moved bold headings into {code} title boxes

...

We'll start with the entity data, a simple object to store the information we'll need. These classes go in an entities sub-package. Unlike the use of the pages sub-package (for page component classes), this is not enforced by Tapestry; it's just a convention (but as we'll see shortly, a handy one).

Code Block
titlesrc/main/java/org/apache/tapestry5/tutorial/entities/Address.java

...

Code Block
package org.apache.tapestry5.tutorial.entities;

import org.apache.tapestry5.tutorial.data.Honorific;

public class Address
{
  private Honorific honorific;

  private String firstName;

  private String lastName;

  private String street1;

  private String street2;

  private String city;

  private String state;

  private String zip;

  private String email;

  private String phone;

  public String getCity()
  {
    return city;
  }

  public String getEmail()
  {
    return email;
  }

  public String getFirstName()
  {
    return firstName;
  }

  public Honorific getHonorific()
  {
    return honorific;
  }

  public String getLastName()
  {
    return lastName;
  }

  public String getPhone()
  {
    return phone;
  }

  public String getState()
  {
    return state;
  }

  public String getStreet1()
  {
    return street1;
  }

  public String getStreet2()
  {
    return street2;
  }

  public String getZip()
  {
    return zip;
  }

  public void setCity(String city)
  {
    this.city = city;
  }

  public void setEmail(String email)
  {
    this.email = email;
  }

  public void setFirstName(String firstName)
  {
    this.firstName = firstName;
  }

  public void setHonorific(Honorific honorific)
  {
    this.honorific = honorific;
  }

  public void setLastName(String lastName)
  {
    this.lastName = lastName;
  }

  public void setPhone(String phone)
  {
    this.phone = phone;
  }

  public void setState(String state)
  {
    this.state = state;
  }

  public void setStreet1(String street1)
  {
    this.street1 = street1;
  }

  public void setStreet2(String street2)
  {
    this.street2 = street2;
  }

  public void setZip(String zip)
  {
    this.zip = zip;
  }
}

It's just a collection of getter and setter methods. We also need to define the enum type, Honorific:

Code Block
titlesrc/main/java/org/apache/tapestry5/tutorial/data/Honorific.java

...

Code Block
package org.apache.tapestry5.tutorial.data;

public enum Honorific
{
  MR, MRS, MISS, DR
}

...

First, we'll update the Index.tml template, to create a link for creating a new page:

Code Block
XML
XML
titlesrc/main/webapp/Index.tml

...

Code Block
XMLXML
    <h1>Address Book</h1>

    <ul>
      <li><t:pagelink page="address/create">Create new address</t:pagelink></li>
    </ul>

Now we need the page, let's start with an empty shell, just to test our navigation.

Code Block
XML
XML
titlesrc/main/webapp/address/CreateAddress.tml

...

Code Block
XMLXML
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
  <head>
    <title>Create New Address</title>
  </head>
  <body>

    <h1>Create New Address</h1>

    <em>coming soon ...</em>

  </body>
</html>

And the corresponding class:

Code Block
titlesrc/main/java/org/apache/tapestry5/tutorial1/pages/address/CreateAddress.java

...

code
package org.apache.tapestry5.tutorial.pages.address;

public class CreateAddress
{

}

...

Code Block
XML
XML
  <t:beaneditform object="address"/>{noformat}

And

...

match

...

that

...

up

...

with

...

a

...

property

...

in

...

the

...

CreateAddress

...

class:

...

@Property
private Address address

Code Block

  @Property
  private Address address

When you refresh the page, you'll see the following:

Image Added

Initial version of the create address form

There have been minor changes to the default CSS since this screenshot was taken; for example, the labels are a bit wider now. In addition, the Honorific field (being optional) would include a blank option, rather than the first real selection, "Mr".

Tapestry's done quite a bit of work here. It has created a form that includes a field for each property. Further, its seen that the honorific property is an enumerated type, and presented that as a drop-down list.

In addition, Tapestry has converted the property names ("city", "email", "firstName") to user presentable labels ("City", "Email", "First Name"). In fact, these are <label> elements, so clicking a label will move the cursor into the corresponding field.

This is an awesome start; it's a presentable interface, quite nice in fact for a few minute's work. But it's far from perfect; let's get started with some customizations.

Changing field order

It looks like the fields are being displayed in alphabetical order, ("city" first, "zip" last). That's not quite the reality, however: If you check the listing for the Address class, you'll see that the getter and setter methods are in alphabetical order (care of Eclipse, which generated all those methods from the fields).

The BeanEditForm works in the order in which the getter methods are defined in the class. Let's reorder them into a more reasonable order:

  • honorific
  • firstName
  • lastName
  • street1
  • street2
  • city
  • state
  • zip
  • email
  • phone
    (This is also the order of in which the fields are defined.)

Because Address is not a component class, it is necessary to restart Jetty to see the effects of these changes.

Once Jetty is restarted, hit the browser's refresh button to see the fields in the correct order:

Image Added
Create address form with fields in proper order

Customizing labels

Tapestry makes it pretty easy to customize the labels used on the fields. It's just a matter of creating a message catalog for the page.

In Tapestry, every page and component may have its own message catalog. This is a standard Java properties file, and it is named the same as the page or component class, with a ".properties" extension. A message catalog consists of a series of lines, each line is a message key and a message value separated with an equals sign.

All it takes is to create a message entry with a particular name: the name of the property suffixed with "-label". As elsewhere, Tapestry is forgiving of case.

When you refresh the page, you'll see the following: !address-v1.png|border=1,width=760,height=439! Initial version of the create address form _There have been minor changes to the default CSS since this screenshot was taken; for example, the labels are a bit wider now. In addition, the Honorific field (being optional) would include a blank option, rather than the first real selection, "Mr"._ Tapestry's done quite a bit of work here. It has created a form that includes a field for each property. Further, its seen that the honorific property is an enumerated type, and presented that as a drop-down list. In addition, Tapestry has converted the property names ("city", "email", "firstName") to user presentable labels ("City", "Email", "First Name"). In fact, these are <label> elements, so clicking a label will move the cursor into the corresponding field. This is an awesome start; it's a presentable interface, quite nice in fact for a few minute's work. But it's far from perfect; let's get started with some customizations. h3. Changing field order It looks like the fields are being displayed in alphabetical order, ("city" first, "zip" last). That's not quite the reality, however: If you check the listing for the Address class, you'll see that the getter and setter methods are in alphabetical order (care of Eclipse, which generated all those methods from the fields). The BeanEditForm works in the order in which the _getter methods_ are defined in the class. Let's reorder them into a more reasonable order: * honorific * firstName * lastName * street1 * street2 * city * state * zip * email * phone (This is also the order of in which the fields are defined.) Because Address is not a component class, it is necessary to restart Jetty to see the effects of these changes. Once Jetty is restarted, hit the browser's refresh button to see the fields in the correct order: !address-v2.png|border=1,width=760,height=439! Create address form with fields in proper order h3. Customizing labels Tapestry makes it pretty easy to customize the labels used on the fields. It's just a matter of creating a _message catalog_ for the page. In Tapestry, every page and component may have its own message catalog. This is a standard Java properties file, and it is named the same as the page or component class, with a ".properties" extension. A message catalog consists of a series of lines, each line is a message key and a message value separated with an equals sign. All it takes is to create a message entry with a particular name: the name of the property suffixed with "-label". As elsewhere, Tapestry is forgiving of case. *
No Format
Code Block
title
src/main/resources/org/apache/tapestry5/tutorial/pages/address/CreateAddress.properties

:*

{noformat}
street1-label=Street 1
street2-label=Street 2
email-label=E-Mail
zip-label=Zip Code
phone-label=Phone Number{noformat}

Since

...

this

...

is

...

a

...

new

...

file

...

(and

...

not

...

a

...

change

...

to

...

an

...

existing

...

file),

...

you

...

may

...

have

...

to

...

restart

...

Jetty

...

to

...

force

...

Tapestry to pick up the change.

Image Added
Create Address form with field labels corrected

We can also customize the options in the drop down list. All we have to do is add some more entries to the message catalog matching the enum names to the desired labels. Update CreateAddress.properties and add:

No Format
 to pick up the change.


!address-v3.png|border=1,width=760,height=446!
Create Address form with field labels corrected

We can also customize the options in the drop down list. All we have to do is add some more entries to the message catalog matching the enum names to the desired labels. Update CreateAddress.properties and add:

{noformat}
MR=Mr.
MRS=Mrs.
DR=Dr.{noformat}

Notice

...

that

...

we

...

don't

...

have

...

to

...

include

...

an

...

option

...

for

...

MISS,

...

because

...

that

...

is

...

converted

...

to

...

"Miss"

...

anyway.

...

You

...

might

...

just

...

want

...

to

...

include

...

it

...

for

...

sake

...

of

...

consistency

...

...

...

the

...

point

...

is,

...

each

...

option

...

label

...

is

...

searched

...

for

...

separately.

...

Lastly,

...

the

...

default

...

label

...

on

...

the

...

submit

...

button

...

is

...

"Create/Update"

...

(BeanEditForm

...

doesn't

...

know

...

how

...

it

...

is

...

being

...

used).

...

Let's

...

change

...

that

...

to

...

"Create

...

Address".

...

That

...

button

...

is

...

a

...

component

...

within

...

the

...

BeanEditForm

...

component.

...

It's

...

not

...

a

...

property,

...

so

...

we

...

can't

...

just

...

put

...

a

...

message

...

into

...

the

...

message

...

catalog,

...

the

...

way

...

we

...

can

...

with

...

the

...

fields.

...

Fortunately,

...

the

...

BeanEditForm

...

component

...

includes

...

a

...

parameter

...

expressly

...

for

...

re-labeling

...

the

...

button.

...

Simply

...

change

...

the

...

CreateAddress

...

component

...

template:

Code Block
XML
XML


{code:XML}
  <t:beaneditform submitlabel="Create Address" object="address"/>

...