Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Fix broken link perAndreas Ernst

Using the BeanEditForm Component

Tapestry includes BeanEditForm is a powerful Tapestry component capable of generating a complete create/edit user interface for a typical JavaBean, BeanEditForm..

Div
stylefloat: right; max-width: 30%; margin: 1em


Panel
borderColor#eee
titleBGColor#eee
titleJumpStart Demos


BeanEditForm analyzes the the properties of the bean, locating just those properties that are readable and writablewriteable. It filters down to properties whose type is mapped to a known editor (this is described in more detail below).

The default ordering for properties is in the order in which the getter methods for the properties are defined. When a super-class defines edittable editable properties, those are ordered before sub-class properties.

...

  • String: as a text field
  • Number: as a text field
  • Enum: as a drop-down list
  • Boolean: as a checkbox
  • Date: as a JavaScript calendar
  • Calendar: as a JavaScript calendar

Resolving a property type to an editor type involves a search up the inheritance hierarchy: thus the super-type of Integer, Long, BigDecimal, etc. is Number, which uses a text field for data entry.

The list of supported property types is extensible (this is documented below).

...

For a class, Tapestry will select the public constructor with the most parameters. If this is not desirable (for example, if you get an exception), then place the @Inject annotation on the constructor Tapestry should use.

...

In some cases, a property may be updatable and of a supported type for editing, but should not be presented to the user for editing: for example, a property that holds the primary key of a database entity. In such a case, the @NonVisual annotation may be applied to the property (either the getter or the setter method).

...

If desired, additional validation may be specified using the @Validate annotation. See Forms and Validation.

As of Tapestry 5.2, validation may also be specified via the containing component's property file, using a key in the form of propertyId-validate (eg: myfield-validate=required).

Property ordering

By default, the order in which properties are presented is as defined above (order of the getter method). This can be overridden using the ReorderProperties class annotation.

Default Label

...

For example, you may want to selectively use a PasswordField component:

Code Block
java
java

  <t:beaneditform object="loginCredentials">
    <t:parameter name="password"><p:password>
      <t:label for="password"/>
      <t:passwordfield t:id="password" value="loginCredentials.password"/>
    </tp:parameter>password>
  </t:beaneditform>

The other fields will render normally (using the built-in editors).

...

The BeanEditForm component operates in terms of a BeanModel, which describes the properties, their presentation order, labels and so forth.

...

The model can be created when the page is first instantiated:

Code Block
java
java

public class MyPage
{
  @Inject
  private BeanModelSource beanModelSource;
  
  @Inject
  private ComponentResources resources;

  @Property(write=false)
  @Retain
  private BeanModel model;

  @Property
  private MyBean bean;
  
  {
     model = beanModelSource.create(MyBean.class, true, resources);
     
     // Make other changes to model here.
  }  

}

And, in the component template, the built model can be passed to the BeanEditForm component explicitly:

Code Block
java
java

  <t:beaneditform  object="bean" model="model"/>

...

Next, you must make contributions to the DataTypeAnalyzer or DefaultDataTypeAnalyzer services to match properties to your new name.

DataTypeAnalyzer is a chain of command that can make match properties to data types based on property type or annotations on the property. In general, DefaultDataTypeAnalyzer is used, as that only needs to consider property type. DefaultDataTypeAnalyzer matches property types to data types, based on a search up the inheritance path.

Code Block
java
java

public static void contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class, String> configuration)
{
  configuration.add(BigDecimal.class, "currency");
}

You must provide an editor for the "currency" data type. An editor is a block of a page of the application; this page is not normally rendered itself, but acts as a container for one or more blocks.

Code Block
java
java

public class AppPropertyEditBlocks
{
    @Property
    @Environmental
    private PropertyEditContext context;
  
    @Component(parameters =
    { "value=context.propertyValue", "label=prop:context.label",
            "translate=prop:currencyTranslator", "validate=prop:currencyValidator",
            "clientId=prop:context.propertyId", "annotationProvider=context" })
    private TextField currency;

    @Inject
    private ComponentResources resources;

    public FieldValidator getCurrencyValidator()
    {
      return context.getValidator(currency);
    }
    
    public FieldTranslator getCurrencyTranslator()
    {
      return context.getTranslator(current);
    }
}

...

The editor is a block inside the component template:

Code Block
java
java

  <t:block id="currency">
    <t:label for="currency"/>
    <t:textfield t:id="currency" size="10"/>
  </t:block>

Finally, we tell the BeanEditForm component about the editor via a contribution to the BeanBlockSource service:

Code Block
java
java

public static void contributeBeanBlockSource(Configuration<BeanBlockContribution> configuration)
{
  configuration.add(new BeanBlockContribution("currency", "AppPropertyEditBlocks", "currency", true));
}

...