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 MarceloLotif: http://wiki.apache.org/tapestry/Tapestry5SelectObject The comment on the change is: added the SelectObject component based on the DanielJue's GenericSelectionModel New page: == SelectObject Component == This is an alternative implementation of the Select core component that allows you to generate a drop down list based on a List<Object> attribute and retrieves the whole object as the result of the selection. See also : * [http://www.phy6.net/wiki/tiki-index.php?page=Tapestry+5+GenericSelectionModel Tapestry5 How to use the SELECT component] * ["Tapestry5DisplayableSelectionModel"] First, you have to add a dependency to your pom.xml. This will add the Apache BeanUtils to your project: {{{ <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils-core</artifactId> <version>1.7.0</version> </dependency> }}} == GenericSelectionModel.java == This is the model that the component will use to render your List. Add it to any package visible to the components package. {{{ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import org.apache.commons.beanutils.BeanUtils; import org.apache.tapestry.OptionGroupModel; import org.apache.tapestry.OptionModel; import org.apache.tapestry.internal.OptionModelImpl; import org.apache.tapestry.util.AbstractSelectModel; /** * @author jued * * @param <T> */ public class GenericSelectionModel<T> extends AbstractSelectModel { private String labelField; private List<T> list; public GenericSelectionModel(List<T> list, String labelField) { this.labelField = labelField; this.list = list; } public List<OptionGroupModel> getOptionGroups() { return null; } public List<OptionModel> getOptions() { List<OptionModel> optionModelList = new ArrayList<OptionModel>(); try { for (T obj : list) { if (labelField == null) { optionModelList.add(new OptionModelImpl(obj + "", false, obj, new String[0])); } else { optionModelList.add(new OptionModelImpl( BeanUtils.getProperty(obj, labelField), false, obj, new String[0])); } } } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } return optionModelList; } } }}} == GenericValueEncoder.java == This is the encoder that the component will use to get your selection. Add it to the same package of the GenericSelectionModel. {{{ import java.lang.reflect.InvocationTargetException; import java.util.List; import org.apache.commons.beanutils.BeanUtils; import org.apache.tapestry.ValueEncoder; public class GenericValueEncoder<T> implements ValueEncoder<T> { private String labelField; private List<T> list; public GenericValueEncoder(List<T> list, String labelField) { this.list = list; this.labelField = labelField; } public String toClient(T obj) { try { if (labelField == null) { return obj + ""; } else { return BeanUtils.getProperty(obj, labelField); } } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } public T toValue(String string) { try { for (T obj : list) { if (labelField == null) { if ((obj + "").equals(string)) { return obj; } } else { if (BeanUtils.getProperty(obj, labelField).equals(string)) { return obj; } } } } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } } }}} == SelectObject.java == This is the Select (org.apache.tapestry.corelib.components) with some simple modifications to use those models above and ommit part of the custom parameters. {{{ import org.apache.tapestry.Binding; import org.apache.tapestry.ComponentResources; import org.apache.tapestry.FieldValidator; import org.apache.tapestry.MarkupWriter; import org.apache.tapestry.OptionModel; import org.apache.tapestry.SelectModel; import org.apache.tapestry.SelectModelVisitor; import org.apache.tapestry.ValidationException; import org.apache.tapestry.ValidationTracker; import org.apache.tapestry.ValueEncoder; import org.apache.tapestry.annotations.BeforeRenderTemplate; import org.apache.tapestry.annotations.Environmental; import org.apache.tapestry.annotations.Inject; import org.apache.tapestry.annotations.Parameter; import org.apache.tapestry.corelib.base.AbstractField; import org.apache.tapestry.internal.util.SelectModelRenderer; import org.apache.tapestry.services.FieldValidatorDefaultSource; import org.apache.tapestry.services.FormSupport; import org.apache.tapestry.services.Request; import org.apache.tapestry.services.ValueEncoderFactory; import org.apache.tapestry.services.ValueEncoderSource; import org.apache.tapestry.util.EnumSelectModel; import org.exemplo.selectComponent.models.GenericSelectionModel; import org.exemplo.selectComponent.models.GenericValueEncoder; /** * Select an item from a list of values, using an [X]HTML <select> element on the client side. * An validation decorations will go around the entire <select> element. * <p> * A core part of this component is the [EMAIL PROTECTED] ValueEncoder} (the encoder parameter) that is used to * convert between server-side values and client-side strings. In many cases, a [EMAIL PROTECTED] ValueEncoder} * can be generated automatically from the type of the value parameter. The * [EMAIL PROTECTED] ValueEncoderSource} service provides an encoder in these situations; it can be overriden * by binding the encoder parameter, or extended by contributing a [EMAIL PROTECTED] ValueEncoderFactory} into * the service's configuration. */ public final class SelectObject extends AbstractField { private class Renderer extends SelectModelRenderer { public Renderer(MarkupWriter writer) { super(writer, _encoder); } @Override protected boolean isOptionSelected(OptionModel optionModel) { Object value = optionModel.getValue(); return value == _value || (value != null && value.equals(_value)); } } @Inject private FieldValidatorDefaultSource _fieldValidatorDefaultSource; @Inject private Locale _locale; @Parameter(required = true) private List<Object> _list; @Parameter private String _labelField = null; // Maybe this should default to property "<componentId>Model"? /** * The model used to identify the option groups and options to be presented to the user. This * can be generated automatically for Enum types. */ // @Parameter(required = true) // private SelectModel _model; private GenericSelectionModel<Object> _model; /** * Allows a specific implementation of [EMAIL PROTECTED] ValueEncoder} to be supplied. This is used to * create client-side string values for the different options. * * @see ValueEncoderSource */ // @Parameter // private ValueEncoder _encoder; private GenericValueEncoder<Object> _encoder; @Inject private Request _request; @Inject private ComponentResources _resources; @Environmental private ValidationTracker _tracker; /** Performs input validation on the value supplied by the user in the form submission. */ @Parameter(defaultPrefix = "validate") @SuppressWarnings("unchecked") private FieldValidator<Object> _validate = NOOP_VALIDATOR; /** The value to read or update. */ @Parameter(required = true, principal = true) private Object _value; @Inject private ValueEncoderSource _valueEncoderSource; @Override protected void processSubmission(FormSupport formSupport, String elementName) { _encoder = new GenericValueEncoder<Object>(_list, _labelField); String primaryKey = _request.getParameter(elementName); Object selectedValue = _encoder.toValue(primaryKey); try { _validate.validate(selectedValue); _value = selectedValue; } catch (ValidationException ex) { _tracker.recordError(this, ex.getMessage()); return; } } void afterRender(MarkupWriter writer) { writer.end(); } void beginRender(MarkupWriter writer) { writer.element("select", "name", getElementName(), "id", getClientId()); _encoder = new GenericValueEncoder<Object>(_list, _labelField); _model = new GenericSelectionModel<Object>(_list, _labelField); // Disabled, informals via mixins } @SuppressWarnings("unchecked") ValueEncoder defaultEncoder() { return _valueEncoderSource.createEncoder("value", _resources); } @SuppressWarnings("unchecked") SelectModel defaultModel() { Class valueType = _resources.getBoundType("value"); if (valueType == null) return null; if (Enum.class.isAssignableFrom(valueType)) return new EnumSelectModel(valueType, _resources.getContainerMessages()); return null; } /** * Computes a default value for the "validate" parameter using * [EMAIL PROTECTED] FieldValidatorDefaultSource}. */ FieldValidator defaultValidate() { Class type = _resources.getBoundType("value"); if (type == null) return null; return _fieldValidatorDefaultSource.createDefaultValidator( this, _resources.getId(), _resources.getContainerMessages(), _locale, type, _resources.getAnnotationProvider("value")); } Binding defaultValue() { return createDefaultParameterBinding("value"); } @BeforeRenderTemplate void options(MarkupWriter writer) { SelectModelVisitor renderer = new Renderer(writer); _model.visit(renderer); } // For testing. void setModel(GenericSelectionModel model) { _model = model; } void setValue(Object value) { _value = value; } void setValueEncoder(GenericValueEncoder encoder) { _encoder = encoder; } } }}} And you're done! == Usage == Using it is very simple. On your Page class, declare the attributes that the component will use: {{{ public class SomePage { private SomeBean _someBean; private List<SomeBean> _beanList; public SomeBean getSomeBean(){ return _someBean; } public void setSomeBean(SomeBean _someBean){ this._someBean = _someBean; } public List<SomeBean> getBeanList(){ return _beanList; } public void setBeanList(List<SomeBean> _beanList){ this._beanList = _beanList; } } }}} Then, on the html file, call the component as shown above (don't forget to populate the list before doing this): {{{ <form t:type="Form"> <t:selectObject list="beanList" value="someBean" labelField="literal:name"/> <t:submit/> </form> }}} The '''labelField''' parameter receive the name of an atribute of the bean class that will be rendered as the options of the drop down list. The component will return to the ''_someBean'' attribute the value of the selection. You can even have a '''List<String>''' as the list to be rendered. In this case, you have to ommit the ''label field'' parameter. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
