PropertySelection

Creates form elements that allow a property of an object to be set from a drop-down list.

Uses a IPropertySelectionModel to map between Java values that will be assigned, and textual labels that will appear in the HTML response.

A useful property selection model is available ( StringPropertySelectionModel , or BeanPropertySelectionModel). You can also create your own model, as illustrated in the examples below.

Note that complex value Objects need to properly implement the Object.equals() method if the correct initial item is to be displayed.

Informal parameters are applied to the <select> tag. To have greater control over the <option> tags, you must use the Select and Option components.

See also: org.apache.tapestry.form.PropertySelection , Select , Option , Radio , RadioGroup , Form , Script

Parameters

Name Type Required Default Description
value Object yes The property to set. During rendering, this property is read, and sets the default value of the selection (if it is null, no element is selected). When the form is submitted, this property is updated based on the new selection.
model IPropertySelectionModel yes The model provides a list of possible labels, and matches those labels against possible values that can be assigned back to the property.
optionRenderer IOptionRenderer yes DefaultOptionRenderer Object used to render the <option>Label</option> elements within the enclosing <select> tags. The default implementation currently handles only writing out the disabled/selected attributes corresponding the methods implemented by IPropertySelectionModel .



It is possible to implement more advanced display semantics of your options list by implementing a custom IOptionRenderer of your own. Things like optgroup and various indentation strategies are typically good candidates for implementing custom renderers.
disabled boolean no false Controls whether the <select> is active or not. A disabled PropertySelection does not update its value parameter. Corresponds to the "disabled" HTML attribute.
displayName String no The user-presentable name for the component, which will be used by a FieldLabel connected to the component.
validators Array or collection of Validator no The validators to apply to the component. Something along the lines of: validators:required .



See also: Validation

Body: removed

Informal parameters: allowed

Reserved parameters: name

Examples

Example 1

The PropertySelection component provides Gender selection drop down list using a StringPropertySelectionModel

<form jwcid="@Form" listener="listener:formSubmit">
 Gender: <select jwcid="@PropertySelection" model="ognl:@com.myexample.DetailsPage@GENDER_MODEL" value="ognl:gender"></select>
 <input type="submit"/>
</form>
public abstract class DetailsPage extends BasePage {
  public static final IPropertySelectionModel GENDER_MODEL =
      new StringPropertySelectionModel(new String[] { "Unspecified", "Female", "Male" });

  public abstract String getGender();

  public void formSubmit(IRequestCycle cycle) {
      // Process form submission
      String genderSelection = getGender();
      ...
  }
}

Example 2 : Custom IOptionRenderer

The optionRenderer parameter allows you complete control over the display of your options list with custom renderer implementations. The following example shows a sample custom renderer implementation for generating a google style drop down actions list. (similar to the gmail drop down actions list)

The resulting option list would look something like:

/**
 * Implementation of {@link IOptionRenderer} that pretty prints options
 * that aren't disabled with padded whitespace at the beginning.
 */
public class FormattedOptionRenderer implements IOptionRenderer {

    // Provided for efficiency / convenience
    public static final IOptionRenderer DEFAULT_INSTANCE = new FormattedOptionRenderer();

    /**
     * {@inheritDoc}
     */
    public void renderOptions(IMarkupWriter writer, IRequestCycle cycle, IPropertySelectionModel model, Object selected) {
        int count = model.getOptionCount();

        for (int i = 0; i < count; i++)
        {
            Object option = model.getOption(i);

            writer.begin("option");
            writer.attribute("value", model.getValue(i));

            if (isEqual(option, selected, model))
                writer.attribute("selected", "selected");

            if (model.isDisabled(i))
                writer.attribute("style", "color: rgb(119, 119, 119);");

            if (i > 0)
                writer.printRaw("&nbsp;");

            writer.print(model.getLabel(i));
            
            writer.end();
            writer.println();
        }
    }

    protected boolean isEqual(Object left, Object right, IPropertySelectionModel model) {

        if (List.class.isInstance(right) && IPrimaryKeyConverter.class.isInstance(model))
        {
            List values = (List) right;
            IPrimaryKeyConverter converter = (IPrimaryKeyConverter) model;

            if (left == null)
                return false;

            for (Object option : values)
                if (converter.getPrimaryKey(option).equals(converter.getPrimaryKey(left)))
                    return true;

            return false;
        }

        // Both null, or same object, then are equal

        if (left == right)
            return true;

        // If one is null, the other isn't, then not equal.
        
        if (left == null || right == null)
            return false;

        // Both non-null; use standard comparison.

        return left.equals(right);
    }
}

Example 3

Provides list of clothing items for the user to select. When the user selects a cloting item from the list the description the label and price is automatically updated. The list of clothing items would typically be loaded from a database.

PurchasePage.html

<body jwcid="@Body">
<form jwcid="@Form" listener="listener:formSubmit">
 <label jwcid="@FieldLabel" field="component:itemSelection">Selection</label>
 <select jwcid="itemSelection@PropertySelection"
       model="ognl:itemSelectionModel"
       value="ognl:clothingItem"
       onchange="javascript:this.form.events.refresh();"
       displayName="Choose an item"></select>
 <input type="submit" value="Show me this item"/>
 <span jwcid="@Conditional" condition="ognl:clothingItem!=null">
 <p>Description: <span jwcid="@Insert" value="ognl:clothingItem.description"/></p>
 <p>Label: <span jwcid="@Insert" value="ognl:clothingItem.label"/></p>
 <p>Price: $<span jwcid="@Insert" value="ognl:clothingItem.price"/></p>
 </span>
</form>
</body>

PurchasePage.java

public abstract class PurchasePage extends BasePage implements PageDetachListener {

  private ItemSelectionModel model = null;

  public abstract Item getClothingItem();
  public abstract void setClothingItem(Item value);

  public ItemSelectionModel getItemSelectionModel() {
    if (model == null) {
      List items = new ArrayList();
      items.add(new Item(1, "Dress", "Cotton full length Summer dress", "CountryClub", "89.95"));
      items.add(new Item(2, "Jacket", "Gorgeous jacket", "CountryClub", "119.95"));
      model = new ItemSelectionModel(items);
    }
    return model;
  }

  public void formSubmit() {
    // Process form submission

  }

  public void pageDetached(PageEvent pageEvent) {
    model = null;
  }

}

Item.java

public class Item implements Serializable {
  private int id;
  private String name;
  private String description;
  private String label;
  private String price;

  public Item(int id, String name, String desc, String label, String price) {
      this.id = id;
      this.name = name;
      this.description = desc;
      this.label = label;
      this.price = price;
  }

  public int getId() { return id;  }

  public String getName() { return name;  }

  public String getDescription() { return description;  }

  public String getLabel() { return label;  }

  public String getPrice() { return price;  }
}

ItemSelectionModel.java

public class ItemSelectionModel implements IPropertySelectionModel, Serializable {
  private List itemList;

  public ItemSelectionModel(List itemList) {
      this.itemList = itemList;
  }

  public int getOptionCount() { return itemList.size(); }

  public Object getOption(int index) {
      return itemList.get(index);
  }

  public String getLabel(int index) {
      return ((Item) itemList.get(index)).getName();
  }

  public String getValue(int index) { return Integer.toString(index); }

  public Object translateValue(String value) {
      return getOption(Integer.parseInt(value));
  }
}