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: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
