You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by Apache Wiki <wi...@apache.org> on 2007/06/19 12:21:49 UTC
[Tapestry Wiki] Update of "Tapestry5HowToCreateAPropertyEditBlock" by fanf
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 fanf:
http://wiki.apache.org/tapestry/Tapestry5HowToCreateAPropertyEditBlock
New page:
= How to create and contribute Property Edit Block =
This little documentation shows how to create a custom Property editor for the [http://tapestry.apache.org/tapestry5/tapestry-core/guide/beaneditform.html BeanEditForm] component.
We will follow the tutorial available on [http://tapestry.apache.org/tapestry5/tapestry-core/guide/beaneditform.html Tapestry 5 BeanEditForm].
Our editor will be functionally equivalent to the Enum editor (a dropdown select), but we want to manage a list of value as source of option for the drop down list in place of an Enum.
In the following part of this doc, ${Tapestry5 java root} represents the tapestry root package (the one configured in your web.xml) and ${Tapestry5 resources root} represents the matching resources package.
== Process to define a new block editor ==
So, the first thing to define is the object that will represent the list of value with a selection.
This class is quite simple: it contains a list of available options (Strng) and an index that point to the selected value. We put it in a data package, apart from Tapestry monitored package.
When initialized, we just need to change the index to use it.
A more generic set of class to create drop down select from object is available [http://www.phy6.net/wiki/tiki-index.php?page=Tapestry+5+GenericSelectionModel here]
{{{
public class DropDownList {
private List<String> options;
private int selected;
/**
* Retrieve the available options. The returned list is
* an unmodifiable view of internal representation
* of options.
* @return unmodifiable list of options
*/
public List<String> getOptions() {...}
/**
* Return the index of the currently selected
* option, or -1 if none selected.
* @return the index
*/
public int getSelected() {...}
/**
* Set the list of available options to "options".
* The list can't be null. The sorting order is
* preserved, and the selected index is reseted to
* -1
* @param List<String> a non null list of options
*/
public void setOptions(List<String> options) {...}
/**
* Set the selected option to corresponding index.
* The parameter must be in the range of options.
* @param selected
*/
public void setSelected(int selected) {...}
/**
* Return the currently selected option if exists,
* null otherwise.
* @return the selected option
*/
public String getOption() {...}
}
}}}
The complete code for that class is available [http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/interldap/interldap-wui-t5/trunk/src/main/java/org/interldap/wui/tapestry/data/DropDownList.java?view=log&rev=127 here]
We have to specify a name corresponding to our class to the `DefaultDataTypeAnalyzer` of tapestry 5 in `${Tapestry5 java root}/services/AppModule.java`:
{{{
public static void contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class, String> configuration) {
configuration.add(DropDownList.class, "dropdown");
}
}}}
([http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/interldap/interldap-wui-t5/trunk/src/main/java/org/interldap/wui/tapestry/services/AppModule.java?view=log&rev=127 here is the code of AppModule.java])
Now that the easy part is done, we have to define the block that will be in charge to transform the `DropDownList` to a select input.
The block has to be defined in the page assigned to property editor block contributions (named `${tapestry5 resources root}/services/AppPropertyEditBlocks.html` as in the the tutorial):
{{{
<div xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<t:block t:id="dropdown">
<t:label for="select"/>
<input t:id="select"/>
</t:block>
</div>
}}}
([http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/interldap/interldap-wui-t5/trunk/src/main/resources/org/interldap/wui/tapestry/pages/AppPropertyEditBlocks.html?view=log&rev=127 complete code of AppPropertyEditBlocks.html])
We will explain the matching Java class (`${Tapestry5 java root}/services/AppPropertyEditBlocks.java`) in the next chapter, as it's the most interesting part :)
Finally, we contribute our new block editor to Tapestry in `${Tapestry5 java root}/services/AppModule.java`:
{{{
public void contributeBeanBlockSource(Configuration<BeanBlockContribution> configuration) {
configuration.add(new BeanBlockContribution("dropdown", "AppPropertyEditBlocks", "dropdown", true));
}
}}}
== Details of `AppPropertyEditBlocks.java` ==
Now that the global infrastructure is in place, we have to deal with the logic of the editor in `AppPropertyEditBlocks.java`.
Basically, we have two things to deals with:
* how the parameters are passed to the property editor,
* and how we implement a drop-down select component in tapestry.
These concerns are addressed with that code:
{{{
@Environmental
private PropertyEditContext context;
public PropertyEditContext getContext() { return context; }
@SuppressWarnings("unused")
@Component(parameters = { "value=selected", "encoder=valueEncoderForSelected",
"validate=prop:context.validator","label=prop:context.label",
"model=selectModelForDropDownList", “clientId=prop:context.propertyId" })
private Select select;
}}}
The environmental `PropertyEditContext` is the object "pushed in the context" of the block editor by the `BeanEditForm` for each properties of the edited bean. It is that object that is used as data source for the editor. So, for us, it will be a `DropDownList` object, (for this example, we don't really care own the bean editor push and pop it to environment, but you can understand it in the [http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java BeanEditForm code], just search for `_environment.push()` / `_environment.pop()` ).
A drop-down list is implemented by the [http://tapestry.apache.org/tapestry5/tapestry-core/component-parameters.html#org.apache.tapestry.corelib.components.select select component] in tapestry 5.
This component is built with a '''model''' that is the source of available options, a '''value''' that is the bi-directional conduit to get/set the selected value, and a '''value encoder''' that translate the value in a displayable shape (a String), and reciprocally (String to value type).
So, we let '''validate''', '''label''' and '''clientId''' parameters to what the `BeanEditForm` put into the context (that's why these parameters begin by '''prop:contex''' ;) and we concentrate to '''value''', '''encoder''' and '''model'''.
=== The value and the `ValueEncoder` ===
With the way `DropDownList` works, for us the value is the index of the selected option (the ''selected'' property). It is this property that will be updated on a form submit.
So we provide a getter/setter for this property, knowing that all we have is the `PropertyEditContext` passed by the environment:
{{{
public int getSelected() {
return ((DropDownList)this.context.getPropertyValue()).getSelected();
}
public void setSelected(int value) {
((DropDownList)this.context.getPropertyValue()).setSelected(value);
}
}}}
Our value encoder has to translate Integer to String, it's not to hard to define:
{{{
public ValueEncoder getValueEncoderForSelected() {
return new ValueEncoder() {
public String toClient(Object value) { return ((Integer)value).toString();}
public Object toValue(String clientValue) { return new Integer(clientValue);}
};
}
}}}
With that, the form is able to update the selected option.
=== The model ===
Select component need a model that provides options. We provide a really minimalist implementation that transform a list of strings to a model (again, a more generic model is exposed [http://www.phy6.net/wiki/tiki-index.php?page=Tapestry+5+GenericSelectionModel here]).
{{{
public class ValueSelectModel extends AbstractSelectModel {
/* the list of options */
private List<OptionModel> optionModels;
/* we just want to create model from list of string... */
public ValueSelectModel(DropDownList dropDownString) {
optionModels = new ArrayList<OptionModel>();
List<String> options = dropDownString.getOptions();
for (int i = 0; i < options.size(); i++){
optionModels.add(new ValueOptionModel(new Integer(i), options.get(i),false,null));
}
}
/* we don't use that... */
public List<OptionGroupModel> getOptionGroups() {return null;}
/* retrieve the list of options */
public List<OptionModel> getOptions() { return this.optionModels; }
/* we have to define what is an option, so we must implement OptionModel */
private class ValueOptionModel implements OptionModel {
[...]
public ValueOptionModel(Object value, String label, boolean disabled, Map<String, String> attrs) {...}
public Map<String, String> getAttributes() {...}
public String getLabel() {...}
public Object getValue() {...}
public boolean isDisabled() {...}
} /* end of class ValueOptionModel */
}
}}}
For an overview of the code, you can look at the complete code of [http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/interldap/interldap-wui-t5/trunk/src/main/java/org/interldap/wui/tapestry/pages/ AppPropertyEditBlocks.java?view=log&rev=127 AppPropertyEditBlocks.java].
And with all that, you should be able to use your new editor to edit class with `DropDownList` properties !
You may see [http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/interldap/interldap-wui-t5/trunk/src/test/java/org/interldap/wui/tapestry/data/Person.java?view=log&rev=127 a person example, with a month selection here].
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org