You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Adam Zimowski <zi...@gmail.com> on 2008/03/25 19:51:40 UTC
Re: T5: SelectModel - a real world example
Is the way I'm building my custom select model the "approved" Tap 5
way? My concern is if OptionModelImpl and SelectModelImpl are still
considered internal Tapestry classes and should be avoided? This stuff
works fine for me and it's fairly elegant (IMHO), I just want to know
if there is a better way.
<div class="w-row">
<div class="w-tlabel"><t:label for="article" />:</div>
<t:select t:id="article" style="width:60%;" t:value="articleId"
t:model="articlesModel" /></div>
@Cached
public SelectModel getArticlesModel() {
final List<SelfHelpArticleBean> articles = getArticles();
return new SelectModel() {
private final SelectModel model;
{
OptionModel[] options = new OptionModel[articles.size()+1];
options[0] = new OptionModelImpl("-- Please Select", 0);
int index = 1;
for(SelfHelpArticleBean article : articles) {
String label = article.getId() +
": " + article.getAnchorBody();
int value = article.getId();
options[index++] = new OptionModelImpl(label, value);
}
model = new SelectModelImpl(options);
}
public List<OptionGroupModel> getOptionGroups() {
return model.getOptionGroups();
}
public List<OptionModel> getOptions() {
return model.getOptions();
}
public void visit(SelectModelVisitor aVisitor) {
model.visit(aVisitor);
}
};
}
On Tue, May 8, 2007 at 12:50 AM, Bill Holloway <bi...@gmail.com> wrote:
> I'm just hoping for a stable, best-practice, and relatively simple way
> to set things up like Selects. Whatever you think is the best
> approach and put in the documentation.
>
> Things like selects should be a snap, IMHO.
>
> Bill
>
>
>
> On 5/7/07, Howard Lewis Ship <hl...@gmail.com> wrote:
> > My approach has to been to keep everything internal if possible. Thus an
> > interface is public, the implementation is internal.
> >
> > If something is truly necessary, such as OptionModelImpl, there are two
> > approaches:
> >
> > 1) Make the implementation class public (possibly breaking existing code
> > that extends from the internal class) .... oh, and probably make it final as
> > well.
> >
> > 2) Define a public factory service for the implementation.
> >
> > Right now, you can actually use the TypeCoercer as a kind of factory; if you
> > pass in a comma-separated string and ask for an SelectModel you'll get it.
> > Here, though, you're looking for something a little better adapted to your
> > entity classes. However, a bare-bones implementation of OptionModel (that
> > always returns false for isDisabled(), and null for getAttributes() ) is
> > only a couple of lines of code.
> >
> > I think T4 fell into a trap of too much convenience stuff exposed as public
> > APIs. I would rather err on the side of over-zealousness for T5. You can
> > take internals public, but not the other way around, and once something is
> > public, it also is (or should be) final.
> >
> > On 5/7/07, Bill Holloway <bi...@gmail.com> wrote:
> > >
> > > I've written similar code -- while remembering that OptionModelImpl is
> > > an "internal" class that Howard, in the documentation, has admonished
> > > us not to use.
> > >
> > > Community, what's the better solution?
> > >
> > > Bill
> > >
> > > On 5/7/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > Eureka!
> > > >
> > > > Finally got it all working. What caused the drop down to not be
> > > > defaulting is the fact that I declared my "Brand" list in two separate
> > > > lists... One for the ValueEncoder and one for the SelectModel. Big no
> > > > no! An "equals" is called on the value from the SelectModel and the
> > > > value from the ValueEncoder, so if they are initialized as separate
> > > > objects in separate lists the framework won't notice that they are equal
> > > > (because they would point to a different memory location). I found that
> > > > the framework also seems to like things better if the List of Brands is
> > > > "@Persist"ed between pages. Here's the final source code that I used to
> > > > get it all working (Enjoy!):
> > > >
> > > > Brand.java (simple POJO):
> > > >
> > > > public class Brand {
> > > >
> > > > private String id;
> > > > private String description;
> > > >
> > > > public Brand() {}
> > > >
> > > > public Brand(String id, String description) {
> > > > this.id = id;
> > > > this.description = description;
> > > > }
> > > >
> > > > public String getId() {
> > > > return id;
> > > > }
> > > >
> > > > public String getDescription() {
> > > > return description;
> > > > }
> > > >
> > > > }
> > > >
> > > >
> > > > Test.java
> > > >
> > > > public class Test {
> > > >
> > > > @Persist
> > > > private Brand brand;
> > > >
> > > > @Persist
> > > > private List<Brand> brands;
> > > >
> > > > public Brand getBrand() {
> > > > return brand;
> > > > }
> > > >
> > > > public void setBrand(Brand brand) {
> > > > this.brand = brand;
> > > > }
> > > >
> > > > private List<Brand> getBrands()
> > > > {
> > > > if(brands == null) {
> > > > brands = new ArrayList<Brand>();
> > > > brands.add(new Brand("1", "Brand 1"));
> > > > brands.add(new Brand("2", "Brand 2"));
> > > > brands.add(new Brand("3", "Brand 3"));
> > > > brands.add(new Brand("4", "Brand 4"));
> > > > }
> > > >
> > > > return brands;
> > > > }
> > > >
> > > > public BrandSelectModel getBrandSelectModel() {
> > > > return new BrandSelectModel(getBrands());
> > > > }
> > > >
> > > > public BrandValueEncoder getBrandValueEncoder() {
> > > > return new BrandValueEncoder(getBrands());
> > > > }
> > > >
> > > > public class BrandValueEncoder implements ValueEncoder<Brand> {
> > > >
> > > > private List<Brand> brands;
> > > >
> > > > public BrandValueEncoder(List<Brand> brands) {
> > > > this.brands = brands;
> > > > }
> > > >
> > > > public String toClient(Brand brand) {
> > > > return brand.getDescription();
> > > > }
> > > >
> > > > public Brand toValue(String string) {
> > > > for(Brand brand : brands) {
> > > >
> > > > if(brand.getDescription().equals(string)) {
> > > > return brand;
> > > > }
> > > > }
> > > > return null;
> > > > }
> > > >
> > > > }
> > > >
> > > > public class BrandSelectModel implements SelectModel {
> > > >
> > > > private List<Brand> brands;
> > > >
> > > > public BrandSelectModel(List<Brand> brands) {
> > > > this.brands = brands;
> > > > }
> > > >
> > > > public List<OptionGroupModel> getOptionGroups() {
> > > > return null;
> > > > }
> > > >
> > > > public List<OptionModel> getOptions() {
> > > > List<OptionModel> optionModelList = new
> > > > ArrayList<OptionModel>();
> > > > for(Brand brand: brands) {
> > > > optionModelList.add(
> > > > new OptionModelImpl(
> > > > brand.getDescription(),
> > > > false,
> > > > brand,
> > > > new String[0]
> > > > )
> > > > );
> > > > }
> > > > return optionModelList;
> > > > }
> > > >
> > > > }
> > > >
> > > > }
> > > >
> > > >
> > > > Test.html
> > > >
> > > > <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
> > > > <t:form>
> > > >
> > > > <select t:type="select" t:id="brand"
> > > > value="brand" model="brandSelectModel"
> > > > encoder="brandValueEncoder"
> > > > onchange="this.form.submit();" />
> > > >
> > > > <br/>
> > > >
> > > > <t:if test="brand">
> > > > ${brand.description}
> > > > </t:if>
> > > >
> > > > </t:form>
> > > > </html>
> > > >
> > > >
> > > > -----Original Message-----
> > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > Sent: Monday, May 07, 2007 12:17 PM
> > > > To: Tapestry users
> > > > Subject: Re: T5: SelectModel - a real world example
> > > >
> > > > Odd that you lost your value; the field is itself persistent (@Persist).
> > > > Unless you are testing on a multi-machine cluster, you shouldn't see any
> > > > problems along these lines!
> > > >
> > > > On 5/7/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > >
> > > > > Impressive! I was injecting that value via Spring to bootstrap it.
> > > > > Makes sense I should have removed that...
> > > > >
> > > > > No errors now... However, the field doesn't appear to be binding on a
> > > >
> > > > > form submission. The encoder and the model appear to be receiving and
> > > >
> > > > > returning the correct values, the brand getter and setter appear to be
> > > >
> > > > > getting called, and the dropdown renders correctly except that it
> > > > > always appears to be reset to the default value...
> > > > >
> > > > > I apologize for being so high-maintenance. If there is a working
> > > > > example of a T5 binding select box anywhere on the web, please point
> > > > > me there and I will leave you alone!
> > > > >
> > > > > Main.html
> > > > >
> > > > > <t:form>
> > > > > <select t:type="select" class="mint_font_black_background"
> > > > > t:id="brand"
> > > > > value="brand" model="brandSelectModel" encoder="brandValueEncoder"
> > > > > onchange="this.form.submit();" />
> > > > > </t:form>
> > > > >
> > > > >
> > > > > Main.java
> > > > >
> > > > > public class Main {
> > > > >
> > > > > @Inject
> > > > > @SpringBean("enterprise")
> > > > > private Enterprise enterprise;
> > > > >
> > > > > @Persist
> > > > > private Brand brand;
> > > > >
> > > > > public Brand getBrand() {
> > > > > return brand;
> > > > > }
> > > > >
> > > > > public void setBrand(Brand brand) {
> > > > > this.brand = brand;
> > > > > }
> > > > >
> > > > > public BrandSelectModel getBrandSelectModel() {
> > > > > return new BrandSelectModel(enterprise.getBrands());
> > > > > }
> > > > >
> > > > > public BrandValueEncoder getBrandValueEncoder() {
> > > > > return new BrandValueEncoder(enterprise.getBrands());
> > > > > }
> > > > >
> > > > > public class BrandValueEncoder implements ValueEncoder<Brand>
> > > > > {
> > > > >
> > > > > private List<Brand> brands;
> > > > >
> > > > > public BrandValueEncoder(List<Brand> brands) {
> > > > > this.brands = brands;
> > > > > }
> > > > >
> > > > > public String toClient(Brand brand) {
> > > > > return brand.getDescription();
> > > > > }
> > > > >
> > > > > public Brand toValue(String string) {
> > > > > for(Brand brand : brands) {
> > > > >
> > > > > if(brand.getDescription().equals(string)) {
> > > > > return brand;
> > > > > }
> > > > > }
> > > > > return null;
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > > public class BrandSelectModel implements SelectModel {
> > > > >
> > > > > private List<Brand> brands;
> > > > >
> > > > > public BrandSelectModel(List<Brand> brands) {
> > > > > this.brands = brands;
> > > > > }
> > > > >
> > > > > public List<OptionGroupModel> getOptionGroups() {
> > > > > return null;
> > > > > }
> > > > >
> > > > > public List<OptionModel> getOptions() {
> > > > > List<OptionModel> optionModelList =
> > > > > new ArrayList<OptionModel>();
> > > > > for(Brand brand: brands) {
> > > > > optionModelList.add(
> > > > > new OptionModelImpl(
> > > > > brand.getDescription(),
> > > > > false,
> > > > > brand,
> > > > > new String[0]
> > > > > )
> > > > > );
> > > > > }
> > > > > return optionModelList;
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > >
> > > > >
> > > > > -----Original Message-----
> > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > Sent: Saturday, May 05, 2007 9:45 PM
> > > > > To: Tapestry users
> > > > > Subject: Re: T5: SelectModel - a real world example
> > > > >
> > > > > What annotations are on the brand field of your Main class? Something
> > > >
> > > > > has changes that field to be read-only, which is usually a sign that a
> > > >
> > > > > value was injected.
> > > > >
> > > > > On 5/4/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > >
> > > > > > Still getting unintuitive errors... I've added the ValueEncoder and
> > > > > > now when I submit the form I get the following stack trace (and yes
> > > > > > the "Main" component has a setBrand(Brand) method, which from the
> > > > > > root
> > > > >
> > > > > > cause exception seems to be the cause of the problem?):
> > > > > >
> > > > > > [ERROR] RequestExceptionHandler Processing of request failed with
> > > > > > uncaught exception:
> > > > > > org.apache.tapestry.ioc.internal.util.TapestryException: Failure
> > > > > > writing parameter value of component com.foo.pages.Main:brand: Field
> > > >
> > > > > > com.foo.pages.Main.brand is read-only. [at
> > > > > > context:WEB-INF/Main.html, line 89, column 278]
> > > > > > java.lang.RuntimeException:
> > > > > > org.apache.tapestry.ioc.internal.util.TapestryException: Failure
> > > > > > writing parameter value of component com.foo.
> > > > > > pages.Main:brand: Field com.foo.pages.Main.brand is read-only. [at
> > > > > > context:WEB-INF/Main.html, line 89, column 278]
> > > > > > at
> > > > > > org.apache.tapestry.corelib.components.Form.onAction(Form.java:356)
> > > > > > at
> > > > > >
> > > > org.apache.tapestry.corelib.components.Form.handleComponentEvent(Form.
> > > > > > ja
> > > > > > va)
> > > > > > at
> > > > > > org.apache.tapestry.internal.structure.ComponentPageElementImpl.hand
> > > > > > le
> > > > > > Ev
> > > > > > ent(ComponentPageElementImpl.java:903)
> > > > > > at
> > > > > > org.apache.tapestry.internal.structure.ComponentPageElementImpl.trig
> > > > > > ge
> > > > > > rE
> > > > > > vent(ComponentPageElementImpl.java:1002)
> > > > > > at
> > > > > > org.apache.tapestry.internal.services.ActionLinkHandlerImpl.handle(A
> > > > > > ct
> > > > > > io
> > > > > > nLinkHandlerImpl.java:100)
> > > > > > at
> > > > > > org.apache.tapestry.internal.services.ActionLinkHandlerImpl.handle(A
> > > > > > ct
> > > > > > io
> > > > > > nLinkHandlerImpl.java:53)
> > > > > > at
> > > > > > $ActionLinkHandler_11258c2d07d.handle($ActionLinkHandler_11258c2d07d
> > > > > > .j
> > > > > > av
> > > > > > a)
> > > > > > at
> > > > > > org.apache.tapestry.internal.services.ComponentActionDispatcher.disp
> > > > > > at
> > > > > > ch
> > > > > > (ComponentActionDispatcher.java:115)
> > > > > > ... 40 more
> > > > > > Caused by: org.apache.tapestry.ioc.internal.util.TapestryException:
> > > > > > Failure writing parameter value of component
> > > > com.foo.pages.Main:brand:
> > > > > > Field com.foo.pages.Main.brand is read-only. [at
> > > > > > context:WEB-INF/Main.html, line 89, column 278]
> > > > > > at
> > > > > >
> > > > org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.
> > > > > > wr
> > > > > > iteParameter(InternalComponentResourcesImpl.java:223)
> > > > > > at
> > > > > > org.apache.tapestry.corelib.components.Select._$update_parameter_val
> > > > > > ue
> > > > > > _0
> > > > > > (Select.java)
> > > > > > at
> > > > > > org.apache.tapestry.corelib.components.Select.processSubmission(Sele
> > > > > > ct
> > > > > > .j
> > > > > > ava:238)
> > > > > > at
> > > > > > org.apache.tapestry.corelib.base.AbstractField.processSubmission(Abs
> > > > > > tr
> > > > > > ac
> > > > > > tField.java:210)
> > > > > > at
> > > > > >
> > > > >
> > > > org.apache.tapestry.corelib.base.AbstractField.access$100(AbstractField.
> > > > > > java:47)
> > > > > > at
> > > > > > org.apache.tapestry.corelib.base.AbstractField$ProcessSubmissionActi
> > > > > > on
> > > > > > .e
> > > > > > xecute(AbstractField.java:116)
> > > > > > at
> > > > > > org.apache.tapestry.corelib.base.AbstractField$ProcessSubmissionActi
> > > > > > on
> > > > > > .e
> > > > > > xecute(AbstractField.java:110)
> > > > > > at
> > > > > > org.apache.tapestry.corelib.components.Form.onAction(Form.java:347)
> > > > > > ... 40 more
> > > > > > Caused by: org.apache.tapestry.ioc.internal.util.TapestryException:
> > > > > > Field com.foo.pages.Main.brand is read-only. [at
> > > > context:WEB-INF/Main.
> > > > > > html, line 89, column 278]
> > > > > > at
> > > > > > org.apache.tapestry.internal.bindings.PropBinding.set(PropBinding.ja
> > > > > > va
> > > > > > :7
> > > > > > 1)
> > > > > > at
> > > > > >
> > > > org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.
> > > > > > wr
> > > > > > iteParameter(InternalComponentResourcesImpl.java:219)
> > > > > > ... 47 more
> > > > > > Caused by: java.lang.RuntimeException: Field
> > > > > > com.foo.pages.Main.brand is read-only.
> > > > > > at com.foo.pages.Main._$write_brand(Main.java)
> > > > > > at com.foo.pages.Main.setBrand(Main.java:92)
> > > > > > at
> > > > > > $PropertyConduit_11258c2d0a9.set($PropertyConduit_11258c2d0a9.java)
> > > > > > at
> > > > > > org.apache.tapestry.internal.bindings.PropBinding.set(PropBinding.ja
> > > > > > va
> > > > > > :6
> > > > > > 7)
> > > > > > ... 48 more
> > > > > >
> > > > > >
> > > > > >
> > > > > > -----Original Message-----
> > > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > > Sent: Friday, May 04, 2007 2:32 PM
> > > > > > To: Tapestry users
> > > > > > Subject: Re: T5: SelectModel - a real world example
> > > > > >
> > > > > > In your OptionModel, the label is the Brand description, and the
> > > > > > value
> > > > >
> > > > > > is the Brand itself.
> > > > > >
> > > > > > You then supply a ValueEncoder that converts between Brands and
> > > > > > brand ids (as strings, for the client side). If Brand is an entity
> > > > > > object, then it may be necessary to have the ValueEncoder talk to
> > > > > > the database
> > > > >
> > > > > > or session store.
> > > > > >
> > > > > > On 5/4/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > > >
> > > > > > > Thanks for the reply Howard.
> > > > > > >
> > > > > > > >> The Select component doesn't know how to create a client-side
> > > > > > > representation of a Brand (it doesn't magically know to use the
> > > > id).
> > > > > > >
> > > > > > > So, then... I guess my question would be... what is the
> > > > > > > BrandSelectModel for? In that object, I'm essentially mapping a
> > > > > > > Brand's "description" to the Brand object.
> > > > > > >
> > > > > > > Just curious what your thoughts are on that...
> > > > > > >
> > > > > > >
> > > > > > > -----Original Message-----
> > > > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > > > Sent: Friday, May 04, 2007 1:42 PM
> > > > > > > To: Tapestry users
> > > > > > > Subject: Re: T5: SelectModel - a real world example
> > > > > > >
> > > > > > > In the simplest case, T5 thinks that the options in the drop down
> > > > > > > list
> > > > > >
> > > > > > > are all strings.
> > > > > > >
> > > > > > > In your case, they are Brands. The Select component doesn't know
> > > > > > > how to create a client-side representation of a Brand (it doesn't
> > > > > > > magically know to use the id).
> > > > > > >
> > > > > > > You must provide a ValueEncoder that can convert between Brands
> > > > > > > and client-side string values. This is the encoder parameter of
> > > > > > > the Select component.
> > > > > > >
> > > > > > >
> > > > > > > On 5/4/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > > > >
> > > > > > > > Not to be harsh, but I don't think I've ever written a select
> > > > > > > > box with
> > > > > > >
> > > > > > > > constant values (Enum). Seems like even Male/Female drop downs
> > > > > > > > need
> > > > > >
> > > > > > > > to be data-driven now-a-days. :->
> > > > > > > >
> > > > > > > > I've started to stub out a very simple "real world example" of a
> > > >
> > > > > > > > select component in T5, but it doesn't appear to be as simple as
> > > >
> > > > > > > > I
> > > > >
> > > > > > > > thought it would be.
> > > > > > > >
> > > > > > > > A shiny nickel to anyone that can spot the flaw, because I sure
> > > > > > > can't...
> > > > > > > > I'm new to Tapestry in general so I could be missing something
> > > > > > > > really mundane here, but seems like it should work in my mind.
> > > > > > > >
> > > > > > > > Here are the players:
> > > > > > > >
> > > > > > > > << THE ERROR >>
> > > > > > > >
> > > > > > > > [ERROR] DefaultRequestExceptionHandler Processing of request
> > > > > > > > failed with uncaught exception: com.foo.data.Brand cannot be
> > > > > > > > cast to java.lang.String
> > > > > > > > java.lang.ClassCastException: com.foo.data.Brand cannot be cast
> > > > > > > > to
> > > > >
> > > > > > > > java.lang.String
> > > > > > > > at
> > > > > > > >
> > > > > > > org.apache.tapestry.corelib.components.Select$1.toClient(Select.ja
> > > > > > > va
> > > > > > > :6
> > > > > > > 2)
> > > > > > > > at
> > > > > > > >
> > > > org.apache.tapestry.corelib.components.Select.writeOptions(Select.
> > > > > > > > ja
> > > > > > > > va
> > > > > > > > :1
> > > > > > > > 94)
> > > > > > > > at
> > > > > > > >
> > > > > > org.apache.tapestry.corelib.components.Select.options(Select.java:16
> > > > > > 9)
> > > > > > > > at
> > > > > > > > org.apache.tapestry.corelib.components.Select.beforeRenderTempla
> > > > > > > > te
> > > > > > > > (S
> > > > > > > > el
> > > > > > > > ec
> > > > > > > > t.java)
> > > > > > > >
> > > > > > > >
> > > > > > > > << Main.html (abridged) >>
> > > > > > > >
> > > > > > > > <t:form>
> > > > > > > > <select t:type="select" t:id="brand" value="brand"
> > > > > > > > model="brandSelectModel"/>
> > > > > > > > </t:form>
> > > > > > > >
> > > > > > > >
> > > > > > > > << Main.java (abridged) >>
> > > > > > > >
> > > > > > > > package com.foo.pages;
> > > > > > > >
> > > > > > > > import com.foo.data.Brand;
> > > > > > > >
> > > > > > > > public class Main {
> > > > > > > >
> > > > > > > > private Brand brand;
> > > > > > > >
> > > > > > > > public Brand getBrand() {
> > > > > > > > return brand;
> > > > > > > > }
> > > > > > > >
> > > > > > > > public void setBrand(Brand brand) {
> > > > > > > > this.brand = brand;
> > > > > > > > }
> > > > > > > >
> > > > > > > > public BrandSelectModel getBrandSelectModel() {
> > > > > > > > return new BrandSelectModel(getBrands());
> > > > > > > > }
> > > > > > > >
> > > > > > > > public List<Brand> getBrands() {
> > > > > > > > List<Brand> brands = new ArrayList<Brand>();
> > > > > > > > brands.add(new Brand("1", "Brand 1"));
> > > > > > > > brands.add(new Brand("2", "Brand 2"));
> > > > > > > > brands.add(new Brand("3", "Brand 3"));
> > > > > > > > return brands;
> > > > > > > > }
> > > > > > > >
> > > > > > > > }
> > > > > > > >
> > > > > > > >
> > > > > > > > << Brand.java (abridged) >>
> > > > > > > >
> > > > > > > > package com.foo.data;
> > > > > > > >
> > > > > > > > public class Brand {
> > > > > > > >
> > > > > > > > private String id;
> > > > > > > > private String description;
> > > > > > > >
> > > > > > > > public Brand() {}
> > > > > > > >
> > > > > > > > public Brand(String id, String description) {
> > > > > > > > this.id = id;
> > > > > > > > this.description = description;
> > > > > > > > }
> > > > > > > >
> > > > > > > > public String getId() {
> > > > > > > > return id;
> > > > > > > > }
> > > > > > > >
> > > > > > > > public String getDescription() {
> > > > > > > > return description;
> > > > > > > > }
> > > > > > > >
> > > > > > > > }
> > > > > > > >
> > > > > > > >
> > > > > > > > << BrandSelectModel.java >>
> > > > > > > >
> > > > > > > > package com.foo.uisupport;
> > > > > > > >
> > > > > > > > import com.foo.data.Brand;
> > > > > > > >
> > > > > > > > public class BrandSelectModel implements SelectModel {
> > > > > > > >
> > > > > > > > private List<Brand> brands;
> > > > > > > >
> > > > > > > > public BrandSelectModel(List<Brand> brands) {
> > > > > > > > this.brands = brands;
> > > > > > > > }
> > > > > > > >
> > > > > > > > public List<OptionGroupModel> getOptionGroups() {
> > > > > > > > return null;
> > > > > > > > }
> > > > > > > >
> > > > > > > > public List<OptionModel> getOptions() {
> > > > > > > > List<OptionModel> optionModelList = new
> > > > > > > > ArrayList<OptionModel>();
> > > > > > > > for(Brand brand: brands) {
> > > > > > > > optionModelList.add(new
> > > > > > > > OptionModelImpl(brand.getDescription(), false, brand, new
> > > > > > String[0]));
> > > > > > > > }
> > > > > > > > return optionModelList;
> > > > > > > > }
> > > > > > > >
> > > > > > > > }
> > > > > > > >
> > > > > > > >
> > > > > > > >
> > > > > > > > ----------------------------------------------------------------
> > > > > > > > --
> > > > > > > > --
> > > > > > > > - To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > > > > >
> > > > > > > >
> > > > > > >
> > > > > > >
> > > > > > > --
> > > > > > > Howard M. Lewis Ship
> > > > > > > TWD Consulting, Inc.
> > > > > > > Independent J2EE / Open-Source Java Consultant Creator and PMC
> > > > > > > Chair, Apache Tapestry Creator, Apache HiveMind
> > > > > > >
> > > > > > > Professional Tapestry training, mentoring, support and project
> > > > work.
> > > > > > > http://howardlewisship.com
> > > > > > >
> > > > > > > ------------------------------------------------------------------
> > > > > > > --
> > > > > > > - To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > > > >
> > > > > > >
> > > > > >
> > > > > >
> > > > > > --
> > > > > > Howard M. Lewis Ship
> > > > > > TWD Consulting, Inc.
> > > > > > Independent J2EE / Open-Source Java Consultant Creator and PMC
> > > > > > Chair, Apache Tapestry Creator, Apache HiveMind
> > > > > >
> > > > > > Professional Tapestry training, mentoring, support and project work.
> > > > > > http://howardlewisship.com
> > > > > >
> > > > > > --------------------------------------------------------------------
> > > > > > - To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > > >
> > > > > >
> > > > >
> > > > >
> > > > > --
> > > > > Howard M. Lewis Ship
> > > > > TWD Consulting, Inc.
> > > > > Independent J2EE / Open-Source Java Consultant Creator and PMC Chair,
> > > > > Apache Tapestry Creator, Apache HiveMind
> > > > >
> > > > > Professional Tapestry training, mentoring, support and project work.
> > > > > http://howardlewisship.com
> > > > >
> > > > > ---------------------------------------------------------------------
> > > > > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > >
> > > > >
> > > >
> > > >
> > > > --
> > > > Howard M. Lewis Ship
> > > > TWD Consulting, Inc.
> > > > Independent J2EE / Open-Source Java Consultant Creator and PMC Chair,
> > > > Apache Tapestry Creator, Apache HiveMind
> > > >
> > > > Professional Tapestry training, mentoring, support and project work.
> > > > http://howardlewisship.com
> > > >
> > > > ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > >
> > > >
> > >
> > >
> > > --
> > > "The future is here. It's just not evenly distributed yet."
> > >
> > > -- Traditional
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > For additional commands, e-mail: users-help@tapestry.apache.org
> > >
> > >
> >
> >
> > --
> > Howard M. Lewis Ship
> > TWD Consulting, Inc.
> > Independent J2EE / Open-Source Java Consultant
> > Creator and PMC Chair, Apache Tapestry
> > Creator, Apache HiveMind
> >
> > Professional Tapestry training, mentoring, support
> > and project work. http://howardlewisship.com
> >
>
>
> --
>
>
> "The future is here. It's just not evenly distributed yet."
>
> -- Traditional
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org
Re: T5: SelectModel - a real world example
Posted by Marcelo Lotif <ml...@gmail.com>.
Adam,
There's a LOT of different suggestions for expanding the Select component on
the wiki, and your's is pretty good and different from the others. I think
you should consider add it to wiki, so other developers will have more
choices to pick until a better solution is not included in the core.
2008/3/25, Adam Zimowski <zi...@gmail.com>:
>
> Is the way I'm building my custom select model the "approved" Tap 5
> way? My concern is if OptionModelImpl and SelectModelImpl are still
> considered internal Tapestry classes and should be avoided? This stuff
> works fine for me and it's fairly elegant (IMHO), I just want to know
> if there is a better way.
>
> <div class="w-row">
> <div class="w-tlabel"><t:label for="article" />:</div>
> <t:select t:id="article" style="width:60%;" t:value="articleId"
> t:model="articlesModel" /></div>
>
>
> @Cached
> public SelectModel getArticlesModel() {
>
> final List<SelfHelpArticleBean> articles = getArticles();
>
> return new SelectModel() {
>
> private final SelectModel model;
>
> {
> OptionModel[] options = new OptionModel[
> articles.size()+1];
> options[0] = new OptionModelImpl("--
> Please Select", 0);
> int index = 1;
> for(SelfHelpArticleBean article :
> articles) {
> String label = article.getId() +
> ":
> " + article.getAnchorBody();
> int value = article.getId();
> options[index++] = new
> OptionModelImpl(label, value);
> }
>
> model = new SelectModelImpl(options);
> }
>
> public List<OptionGroupModel> getOptionGroups() {
> return model.getOptionGroups();
> }
>
> public List<OptionModel> getOptions() {
> return model.getOptions();
> }
>
> public void visit(SelectModelVisitor aVisitor) {
> model.visit(aVisitor);
> }
>
> };
>
> }
>
>
> On Tue, May 8, 2007 at 12:50 AM, Bill Holloway <bi...@gmail.com>
> wrote:
> > I'm just hoping for a stable, best-practice, and relatively simple way
> > to set things up like Selects. Whatever you think is the best
> > approach and put in the documentation.
> >
> > Things like selects should be a snap, IMHO.
> >
> > Bill
> >
> >
> >
> > On 5/7/07, Howard Lewis Ship <hl...@gmail.com> wrote:
> > > My approach has to been to keep everything internal if possible. Thus
> an
> > > interface is public, the implementation is internal.
> > >
> > > If something is truly necessary, such as OptionModelImpl, there are
> two
> > > approaches:
> > >
> > > 1) Make the implementation class public (possibly breaking existing
> code
> > > that extends from the internal class) .... oh, and probably make it
> final as
> > > well.
> > >
> > > 2) Define a public factory service for the implementation.
> > >
> > > Right now, you can actually use the TypeCoercer as a kind of factory;
> if you
> > > pass in a comma-separated string and ask for an SelectModel you'll
> get it.
> > > Here, though, you're looking for something a little better adapted to
> your
> > > entity classes. However, a bare-bones implementation of OptionModel
> (that
> > > always returns false for isDisabled(), and null for getAttributes() )
> is
> > > only a couple of lines of code.
> > >
> > > I think T4 fell into a trap of too much convenience stuff exposed as
> public
> > > APIs. I would rather err on the side of over-zealousness for
> T5. You can
> > > take internals public, but not the other way around, and once
> something is
> > > public, it also is (or should be) final.
> > >
> > > On 5/7/07, Bill Holloway <bi...@gmail.com> wrote:
> > > >
> > > > I've written similar code -- while remembering that OptionModelImpl
> is
> > > > an "internal" class that Howard, in the documentation, has
> admonished
> > > > us not to use.
> > > >
> > > > Community, what's the better solution?
> > > >
> > > > Bill
> > > >
> > > > On 5/7/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > Eureka!
> > > > >
> > > > > Finally got it all working. What caused the drop down to not be
> > > > > defaulting is the fact that I declared my "Brand" list in two
> separate
> > > > > lists... One for the ValueEncoder and one for the
> SelectModel. Big no
> > > > > no! An "equals" is called on the value from the SelectModel and
> the
> > > > > value from the ValueEncoder, so if they are initialized as
> separate
> > > > > objects in separate lists the framework won't notice that they
> are equal
> > > > > (because they would point to a different memory location). I
> found that
> > > > > the framework also seems to like things better if the List of
> Brands is
> > > > > "@Persist"ed between pages. Here's the final source code that I
> used to
> > > > > get it all working (Enjoy!):
> > > > >
> > > > > Brand.java (simple POJO):
> > > > >
> > > > > public class Brand {
> > > > >
> > > > > private String id;
> > > > > private String description;
> > > > >
> > > > > public Brand() {}
> > > > >
> > > > > public Brand(String id, String description) {
> > > > > this.id = id;
> > > > > this.description = description;
> > > > > }
> > > > >
> > > > > public String getId() {
> > > > > return id;
> > > > > }
> > > > >
> > > > > public String getDescription() {
> > > > > return description;
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > >
> > > > > Test.java
> > > > >
> > > > > public class Test {
> > > > >
> > > > > @Persist
> > > > > private Brand brand;
> > > > >
> > > > > @Persist
> > > > > private List<Brand> brands;
> > > > >
> > > > > public Brand getBrand() {
> > > > > return brand;
> > > > > }
> > > > >
> > > > > public void setBrand(Brand brand) {
> > > > > this.brand = brand;
> > > > > }
> > > > >
> > > > > private List<Brand> getBrands()
> > > > > {
> > > > > if(brands == null) {
> > > > > brands = new ArrayList<Brand>();
> > > > > brands.add(new Brand("1", "Brand 1"));
> > > > > brands.add(new Brand("2", "Brand 2"));
> > > > > brands.add(new Brand("3", "Brand 3"));
> > > > > brands.add(new Brand("4", "Brand 4"));
> > > > > }
> > > > >
> > > > > return brands;
> > > > > }
> > > > >
> > > > > public BrandSelectModel getBrandSelectModel() {
> > > > > return new BrandSelectModel(getBrands());
> > > > > }
> > > > >
> > > > > public BrandValueEncoder getBrandValueEncoder() {
> > > > > return new BrandValueEncoder(getBrands());
> > > > > }
> > > > >
> > > > > public class BrandValueEncoder implements
> ValueEncoder<Brand> {
> > > > >
> > > > > private List<Brand> brands;
> > > > >
> > > > > public BrandValueEncoder(List<Brand> brands) {
> > > > > this.brands = brands;
> > > > > }
> > > > >
> > > > > public String toClient(Brand brand) {
> > > > > return brand.getDescription();
> > > > > }
> > > > >
> > > > > public Brand toValue(String string) {
> > > > > for(Brand brand : brands) {
> > > > >
> > > > > if(brand.getDescription().equals(string)) {
> > > > > return brand;
> > > > > }
> > > > > }
> > > > > return null;
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > > public class BrandSelectModel implements SelectModel {
> > > > >
> > > > > private List<Brand> brands;
> > > > >
> > > > > public BrandSelectModel(List<Brand> brands) {
> > > > > this.brands = brands;
> > > > > }
> > > > >
> > > > > public List<OptionGroupModel> getOptionGroups() {
> > > > > return null;
> > > > > }
> > > > >
> > > > > public List<OptionModel> getOptions() {
> > > > > List<OptionModel> optionModelList = new
> > > > > ArrayList<OptionModel>();
> > > > > for(Brand brand: brands) {
> > > > > optionModelList.add(
> > > > > new OptionModelImpl(
> > > > >
> brand.getDescription(),
> > > > > false,
> > > > > brand,
> > > > > new String[0]
> > > > > )
> > > > > );
> > > > > }
> > > > > return optionModelList;
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > >
> > > > > Test.html
> > > > >
> > > > > <html xmlns:t="
> http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
> > > > > <t:form>
> > > > >
> > > > > <select t:type="select" t:id="brand"
> > > > > value="brand" model="brandSelectModel"
> > > > > encoder="brandValueEncoder"
> > > > > onchange="this.form.submit();" />
> > > > >
> > > > > <br/>
> > > > >
> > > > > <t:if test="brand">
> > > > > ${brand.description}
> > > > > </t:if>
> > > > >
> > > > > </t:form>
> > > > > </html>
> > > > >
> > > > >
> > > > > -----Original Message-----
> > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > Sent: Monday, May 07, 2007 12:17 PM
> > > > > To: Tapestry users
> > > > > Subject: Re: T5: SelectModel - a real world example
> > > > >
> > > > > Odd that you lost your value; the field is itself persistent
> (@Persist).
> > > > > Unless you are testing on a multi-machine cluster, you shouldn't
> see any
> > > > > problems along these lines!
> > > > >
> > > > > On 5/7/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > >
> > > > > > Impressive! I was injecting that value via Spring to bootstrap
> it.
> > > > > > Makes sense I should have removed that...
> > > > > >
> > > > > > No errors now... However, the field doesn't appear to be
> binding on a
> > > > >
> > > > > > form submission. The encoder and the model appear to be
> receiving and
> > > > >
> > > > > > returning the correct values, the brand getter and setter
> appear to be
> > > > >
> > > > > > getting called, and the dropdown renders correctly except that
> it
> > > > > > always appears to be reset to the default value...
> > > > > >
> > > > > > I apologize for being so high-maintenance. If there is a
> working
> > > > > > example of a T5 binding select box anywhere on the web, please
> point
> > > > > > me there and I will leave you alone!
> > > > > >
> > > > > > Main.html
> > > > > >
> > > > > > <t:form>
> > > > > > <select t:type="select" class="mint_font_black_background"
> > > > > > t:id="brand"
> > > > > > value="brand" model="brandSelectModel"
> encoder="brandValueEncoder"
> > > > > > onchange="this.form.submit();" />
> > > > > > </t:form>
> > > > > >
> > > > > >
> > > > > > Main.java
> > > > > >
> > > > > > public class Main {
> > > > > >
> > > > > > @Inject
> > > > > > @SpringBean("enterprise")
> > > > > > private Enterprise enterprise;
> > > > > >
> > > > > > @Persist
> > > > > > private Brand brand;
> > > > > >
> > > > > > public Brand getBrand() {
> > > > > > return brand;
> > > > > > }
> > > > > >
> > > > > > public void setBrand(Brand brand) {
> > > > > > this.brand = brand;
> > > > > > }
> > > > > >
> > > > > > public BrandSelectModel getBrandSelectModel() {
> > > > > > return new BrandSelectModel(
> enterprise.getBrands());
> > > > > > }
> > > > > >
> > > > > > public BrandValueEncoder getBrandValueEncoder() {
> > > > > > return new BrandValueEncoder(
> enterprise.getBrands());
> > > > > > }
> > > > > >
> > > > > > public class BrandValueEncoder implements
> ValueEncoder<Brand>
> > > > > > {
> > > > > >
> > > > > > private List<Brand> brands;
> > > > > >
> > > > > > public BrandValueEncoder(List<Brand> brands) {
> > > > > > this.brands = brands;
> > > > > > }
> > > > > >
> > > > > > public String toClient(Brand brand) {
> > > > > > return brand.getDescription();
> > > > > > }
> > > > > >
> > > > > > public Brand toValue(String string) {
> > > > > > for(Brand brand : brands) {
> > > > > >
> > > > > > if(brand.getDescription().equals(string)) {
> > > > > > return brand;
> > > > > > }
> > > > > > }
> > > > > > return null;
> > > > > > }
> > > > > >
> > > > > > }
> > > > > >
> > > > > > public class BrandSelectModel implements SelectModel {
> > > > > >
> > > > > > private List<Brand> brands;
> > > > > >
> > > > > > public BrandSelectModel(List<Brand> brands) {
> > > > > > this.brands = brands;
> > > > > > }
> > > > > >
> > > > > > public List<OptionGroupModel> getOptionGroups()
> {
> > > > > > return null;
> > > > > > }
> > > > > >
> > > > > > public List<OptionModel> getOptions() {
> > > > > > List<OptionModel> optionModelList =
> > > > > > new ArrayList<OptionModel>();
> > > > > > for(Brand brand: brands) {
> > > > > > optionModelList.add(
> > > > > > new OptionModelImpl(
> > > > > > brand.getDescription(),
> > > > > > false,
> > > > > > brand,
> > > > > > new String[0]
> > > > > > )
> > > > > > );
> > > > > > }
> > > > > > return optionModelList;
> > > > > > }
> > > > > >
> > > > > > }
> > > > > >
> > > > > > }
> > > > > >
> > > > > >
> > > > > >
> > > > > > -----Original Message-----
> > > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > > Sent: Saturday, May 05, 2007 9:45 PM
> > > > > > To: Tapestry users
> > > > > > Subject: Re: T5: SelectModel - a real world example
> > > > > >
> > > > > > What annotations are on the brand field of your Main
> class? Something
> > > > >
> > > > > > has changes that field to be read-only, which is usually a sign
> that a
> > > > >
> > > > > > value was injected.
> > > > > >
> > > > > > On 5/4/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > > >
> > > > > > > Still getting unintuitive errors... I've added the
> ValueEncoder and
> > > > > > > now when I submit the form I get the following stack trace
> (and yes
> > > > > > > the "Main" component has a setBrand(Brand) method, which from
> the
> > > > > > > root
> > > > > >
> > > > > > > cause exception seems to be the cause of the problem?):
> > > > > > >
> > > > > > > [ERROR] RequestExceptionHandler Processing of request failed
> with
> > > > > > > uncaught exception:
> > > > > > > org.apache.tapestry.ioc.internal.util.TapestryException:
> Failure
> > > > > > > writing parameter value of component
> com.foo.pages.Main:brand: Field
> > > > >
> > > > > > > com.foo.pages.Main.brand is read-only. [at
> > > > > > > context:WEB-INF/Main.html, line 89, column 278]
> > > > > > > java.lang.RuntimeException:
> > > > > > > org.apache.tapestry.ioc.internal.util.TapestryException:
> Failure
> > > > > > > writing parameter value of component com.foo.
> > > > > > > pages.Main:brand: Field com.foo.pages.Main.brand is
> read-only. [at
> > > > > > > context:WEB-INF/Main.html, line 89, column 278]
> > > > > > > at
> > > > > > > org.apache.tapestry.corelib.components.Form.onAction(
> Form.java:356)
> > > > > > > at
> > > > > > >
> > > > > org.apache.tapestry.corelib.components.Form.handleComponentEvent
> (Form.
> > > > > > > ja
> > > > > > > va)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.internal.structure.ComponentPageElementImpl.hand
> > > > > > > le
> > > > > > > Ev
> > > > > > > ent(ComponentPageElementImpl.java:903)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.internal.structure.ComponentPageElementImpl.trig
> > > > > > > ge
> > > > > > > rE
> > > > > > > vent(ComponentPageElementImpl.java:1002)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.internal.services.ActionLinkHandlerImpl.handle(A
> > > > > > > ct
> > > > > > > io
> > > > > > > nLinkHandlerImpl.java:100)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.internal.services.ActionLinkHandlerImpl.handle(A
> > > > > > > ct
> > > > > > > io
> > > > > > > nLinkHandlerImpl.java:53)
> > > > > > > at
> > > > > > >
> $ActionLinkHandler_11258c2d07d.handle($ActionLinkHandler_11258c2d07d
> > > > > > > .j
> > > > > > > av
> > > > > > > a)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.internal.services.ComponentActionDispatcher.disp
> > > > > > > at
> > > > > > > ch
> > > > > > > (ComponentActionDispatcher.java:115)
> > > > > > > ... 40 more
> > > > > > > Caused by:
> org.apache.tapestry.ioc.internal.util.TapestryException:
> > > > > > > Failure writing parameter value of component
> > > > > com.foo.pages.Main:brand:
> > > > > > > Field com.foo.pages.Main.brand is read-only. [at
> > > > > > > context:WEB-INF/Main.html, line 89, column 278]
> > > > > > > at
> > > > > > >
> > > > >
> org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.
> > > > > > > wr
> > > > > > > iteParameter(InternalComponentResourcesImpl.java:223)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.corelib.components.Select._$update_parameter_val
> > > > > > > ue
> > > > > > > _0
> > > > > > > (Select.java)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.corelib.components.Select.processSubmission(Sele
> > > > > > > ct
> > > > > > > .j
> > > > > > > ava:238)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.corelib.base.AbstractField.processSubmission(Abs
> > > > > > > tr
> > > > > > > ac
> > > > > > > tField.java:210)
> > > > > > > at
> > > > > > >
> > > > > >
> > > > > org.apache.tapestry.corelib.base.AbstractField.access$100
> (AbstractField.
> > > > > > > java:47)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.corelib.base.AbstractField$ProcessSubmissionActi
> > > > > > > on
> > > > > > > .e
> > > > > > > xecute(AbstractField.java:116)
> > > > > > > at
> > > > > > >
> org.apache.tapestry.corelib.base.AbstractField$ProcessSubmissionActi
> > > > > > > on
> > > > > > > .e
> > > > > > > xecute(AbstractField.java:110)
> > > > > > > at
> > > > > > > org.apache.tapestry.corelib.components.Form.onAction(
> Form.java:347)
> > > > > > > ... 40 more
> > > > > > > Caused by:
> org.apache.tapestry.ioc.internal.util.TapestryException:
> > > > > > > Field com.foo.pages.Main.brand is read-only. [at
> > > > > context:WEB-INF/Main.
> > > > > > > html, line 89, column 278]
> > > > > > > at
> > > > > > > org.apache.tapestry.internal.bindings.PropBinding.set(
> PropBinding.ja
> > > > > > > va
> > > > > > > :7
> > > > > > > 1)
> > > > > > > at
> > > > > > >
> > > > >
> org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.
> > > > > > > wr
> > > > > > > iteParameter(InternalComponentResourcesImpl.java:219)
> > > > > > > ... 47 more
> > > > > > > Caused by: java.lang.RuntimeException: Field
> > > > > > > com.foo.pages.Main.brand is read-only.
> > > > > > > at com.foo.pages.Main._$write_brand(Main.java)
> > > > > > > at com.foo.pages.Main.setBrand(Main.java:92)
> > > > > > > at
> > > > > > >
> $PropertyConduit_11258c2d0a9.set($PropertyConduit_11258c2d0a9.java)
> > > > > > > at
> > > > > > > org.apache.tapestry.internal.bindings.PropBinding.set(
> PropBinding.ja
> > > > > > > va
> > > > > > > :6
> > > > > > > 7)
> > > > > > > ... 48 more
> > > > > > >
> > > > > > >
> > > > > > >
> > > > > > > -----Original Message-----
> > > > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > > > Sent: Friday, May 04, 2007 2:32 PM
> > > > > > > To: Tapestry users
> > > > > > > Subject: Re: T5: SelectModel - a real world example
> > > > > > >
> > > > > > > In your OptionModel, the label is the Brand description, and
> the
> > > > > > > value
> > > > > >
> > > > > > > is the Brand itself.
> > > > > > >
> > > > > > > You then supply a ValueEncoder that converts between Brands
> and
> > > > > > > brand ids (as strings, for the client side). If Brand is an
> entity
> > > > > > > object, then it may be necessary to have the ValueEncoder
> talk to
> > > > > > > the database
> > > > > >
> > > > > > > or session store.
> > > > > > >
> > > > > > > On 5/4/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > > > >
> > > > > > > > Thanks for the reply Howard.
> > > > > > > >
> > > > > > > > >> The Select component doesn't know how to create a
> client-side
> > > > > > > > representation of a Brand (it doesn't magically know to use
> the
> > > > > id).
> > > > > > > >
> > > > > > > > So, then... I guess my question would be... what is the
> > > > > > > > BrandSelectModel for? In that object, I'm essentially
> mapping a
> > > > > > > > Brand's "description" to the Brand object.
> > > > > > > >
> > > > > > > > Just curious what your thoughts are on that...
> > > > > > > >
> > > > > > > >
> > > > > > > > -----Original Message-----
> > > > > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > > > > Sent: Friday, May 04, 2007 1:42 PM
> > > > > > > > To: Tapestry users
> > > > > > > > Subject: Re: T5: SelectModel - a real world example
> > > > > > > >
> > > > > > > > In the simplest case, T5 thinks that the options in the
> drop down
> > > > > > > > list
> > > > > > >
> > > > > > > > are all strings.
> > > > > > > >
> > > > > > > > In your case, they are Brands. The Select component
> doesn't know
> > > > > > > > how to create a client-side representation of a Brand (it
> doesn't
> > > > > > > > magically know to use the id).
> > > > > > > >
> > > > > > > > You must provide a ValueEncoder that can convert between
> Brands
> > > > > > > > and client-side string values. This is the encoder
> parameter of
> > > > > > > > the Select component.
> > > > > > > >
> > > > > > > >
> > > > > > > > On 5/4/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > > > > >
> > > > > > > > > Not to be harsh, but I don't think I've ever written a
> select
> > > > > > > > > box with
> > > > > > > >
> > > > > > > > > constant values (Enum). Seems like even Male/Female drop
> downs
> > > > > > > > > need
> > > > > > >
> > > > > > > > > to be data-driven now-a-days. :->
> > > > > > > > >
> > > > > > > > > I've started to stub out a very simple "real world
> example" of a
> > > > >
> > > > > > > > > select component in T5, but it doesn't appear to be as
> simple as
> > > > >
> > > > > > > > > I
> > > > > >
> > > > > > > > > thought it would be.
> > > > > > > > >
> > > > > > > > > A shiny nickel to anyone that can spot the flaw, because
> I sure
> > > > > > > > can't...
> > > > > > > > > I'm new to Tapestry in general so I could be missing
> something
> > > > > > > > > really mundane here, but seems like it should work in my
> mind.
> > > > > > > > >
> > > > > > > > > Here are the players:
> > > > > > > > >
> > > > > > > > > << THE ERROR >>
> > > > > > > > >
> > > > > > > > > [ERROR] DefaultRequestExceptionHandler Processing of
> request
> > > > > > > > > failed with uncaught exception: com.foo.data.Brand cannot
> be
> > > > > > > > > cast to java.lang.String
> > > > > > > > > java.lang.ClassCastException: com.foo.data.Brand cannot
> be cast
> > > > > > > > > to
> > > > > >
> > > > > > > > > java.lang.String
> > > > > > > > > at
> > > > > > > > >
> > > > > > > > org.apache.tapestry.corelib.components.Select$1.toClient(
> Select.ja
> > > > > > > > va
> > > > > > > > :6
> > > > > > > > 2)
> > > > > > > > > at
> > > > > > > > >
> > > > > org.apache.tapestry.corelib.components.Select.writeOptions
> (Select.
> > > > > > > > > ja
> > > > > > > > > va
> > > > > > > > > :1
> > > > > > > > > 94)
> > > > > > > > > at
> > > > > > > > >
> > > > > > > org.apache.tapestry.corelib.components.Select.options(
> Select.java:16
> > > > > > > 9)
> > > > > > > > > at
> > > > > > > > >
> org.apache.tapestry.corelib.components.Select.beforeRenderTempla
> > > > > > > > > te
> > > > > > > > > (S
> > > > > > > > > el
> > > > > > > > > ec
> > > > > > > > > t.java)
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > << Main.html (abridged) >>
> > > > > > > > >
> > > > > > > > > <t:form>
> > > > > > > > > <select t:type="select" t:id="brand"
> value="brand"
> > > > > > > > > model="brandSelectModel"/>
> > > > > > > > > </t:form>
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > << Main.java (abridged) >>
> > > > > > > > >
> > > > > > > > > package com.foo.pages;
> > > > > > > > >
> > > > > > > > > import com.foo.data.Brand;
> > > > > > > > >
> > > > > > > > > public class Main {
> > > > > > > > >
> > > > > > > > > private Brand brand;
> > > > > > > > >
> > > > > > > > > public Brand getBrand() {
> > > > > > > > > return brand;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public void setBrand(Brand brand) {
> > > > > > > > > this.brand = brand;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public BrandSelectModel getBrandSelectModel() {
> > > > > > > > > return new BrandSelectModel(getBrands());
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public List<Brand> getBrands() {
> > > > > > > > > List<Brand> brands = new
> ArrayList<Brand>();
> > > > > > > > > brands.add(new Brand("1", "Brand 1"));
> > > > > > > > > brands.add(new Brand("2", "Brand 2"));
> > > > > > > > > brands.add(new Brand("3", "Brand 3"));
> > > > > > > > > return brands;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > << Brand.java (abridged) >>
> > > > > > > > >
> > > > > > > > > package com.foo.data;
> > > > > > > > >
> > > > > > > > > public class Brand {
> > > > > > > > >
> > > > > > > > > private String id;
> > > > > > > > > private String description;
> > > > > > > > >
> > > > > > > > > public Brand() {}
> > > > > > > > >
> > > > > > > > > public Brand(String id, String description) {
> > > > > > > > > this.id = id;
> > > > > > > > > this.description = description;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public String getId() {
> > > > > > > > > return id;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public String getDescription() {
> > > > > > > > > return description;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > << BrandSelectModel.java >>
> > > > > > > > >
> > > > > > > > > package com.foo.uisupport;
> > > > > > > > >
> > > > > > > > > import com.foo.data.Brand;
> > > > > > > > >
> > > > > > > > > public class BrandSelectModel implements SelectModel {
> > > > > > > > >
> > > > > > > > > private List<Brand> brands;
> > > > > > > > >
> > > > > > > > > public BrandSelectModel(List<Brand> brands) {
> > > > > > > > > this.brands = brands;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public List<OptionGroupModel> getOptionGroups() {
> > > > > > > > > return null;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public List<OptionModel> getOptions() {
> > > > > > > > > List<OptionModel> optionModelList = new
> > > > > > > > > ArrayList<OptionModel>();
> > > > > > > > > for(Brand brand: brands) {
> > > > > > > > > optionModelList.add(new
> > > > > > > > > OptionModelImpl(brand.getDescription(), false, brand, new
> > > > > > > String[0]));
> > > > > > > > > }
> > > > > > > > > return optionModelList;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > >
> > > > > > > > >
> > > > > > > > >
> ----------------------------------------------------------------
> > > > > > > > > --
> > > > > > > > > --
> > > > > > > > > - To unsubscribe, e-mail:
> users-unsubscribe@tapestry.apache.org
> > > > > > > > > For additional commands, e-mail:
> users-help@tapestry.apache.org
> > > > > > > > >
> > > > > > > > >
> > > > > > > >
> > > > > > > >
> > > > > > > > --
> > > > > > > > Howard M. Lewis Ship
> > > > > > > > TWD Consulting, Inc.
> > > > > > > > Independent J2EE / Open-Source Java Consultant Creator and
> PMC
> > > > > > > > Chair, Apache Tapestry Creator, Apache HiveMind
> > > > > > > >
> > > > > > > > Professional Tapestry training, mentoring, support and
> project
> > > > > work.
> > > > > > > > http://howardlewisship.com
> > > > > > > >
> > > > > > > >
> ------------------------------------------------------------------
> > > > > > > > --
> > > > > > > > - To unsubscribe, e-mail:
> users-unsubscribe@tapestry.apache.org
> > > > > > > > For additional commands, e-mail:
> users-help@tapestry.apache.org
> > > > > > > >
> > > > > > > >
> > > > > > >
> > > > > > >
> > > > > > > --
> > > > > > > Howard M. Lewis Ship
> > > > > > > TWD Consulting, Inc.
> > > > > > > Independent J2EE / Open-Source Java Consultant Creator and
> PMC
> > > > > > > Chair, Apache Tapestry Creator, Apache HiveMind
> > > > > > >
> > > > > > > Professional Tapestry training, mentoring, support and
> project work.
> > > > > > > http://howardlewisship.com
> > > > > > >
> > > > > > >
> --------------------------------------------------------------------
> > > > > > > - To unsubscribe, e-mail:
> users-unsubscribe@tapestry.apache.org
> > > > > > > For additional commands, e-mail:
> users-help@tapestry.apache.org
> > > > > > >
> > > > > > >
> > > > > >
> > > > > >
> > > > > > --
> > > > > > Howard M. Lewis Ship
> > > > > > TWD Consulting, Inc.
> > > > > > Independent J2EE / Open-Source Java Consultant Creator and PMC
> Chair,
> > > > > > Apache Tapestry Creator, Apache HiveMind
> > > > > >
> > > > > > Professional Tapestry training, mentoring, support and project
> work.
> > > > > > http://howardlewisship.com
> > > > > >
> > > > > >
> ---------------------------------------------------------------------
> > > > > > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > > >
> > > > > >
> > > > >
> > > > >
> > > > > --
> > > > > Howard M. Lewis Ship
> > > > > TWD Consulting, Inc.
> > > > > Independent J2EE / Open-Source Java Consultant Creator and PMC
> Chair,
> > > > > Apache Tapestry Creator, Apache HiveMind
> > > > >
> > > > > Professional Tapestry training, mentoring, support and project
> work.
> > > > > http://howardlewisship.com
> > > > >
> > > > >
> ---------------------------------------------------------------------
> > > > > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > >
> > > > >
> > > >
> > > >
> > > > --
> > > > "The future is here. It's just not evenly distributed yet."
> > > >
> > > > -- Traditional
> > > >
> > > >
> ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > >
> > > >
> > >
> > >
> > > --
> > > Howard M. Lewis Ship
> > > TWD Consulting, Inc.
> > > Independent J2EE / Open-Source Java Consultant
> > > Creator and PMC Chair, Apache Tapestry
> > > Creator, Apache HiveMind
> > >
> > > Professional Tapestry training, mentoring, support
> > > and project work. http://howardlewisship.com
> > >
> >
> >
> > --
> >
> >
> > "The future is here. It's just not evenly distributed yet."
> >
> > -- Traditional
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > For additional commands, e-mail: users-help@tapestry.apache.org
> >
> >
>
>
> ---------------------------------------------------------------------
>
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
--
Atenciosamente,
Marcelo Lotif
Re: T5: SelectModel - a real world example
Posted by Howard Lewis Ship <hl...@gmail.com>.
Use of internal classes isn't forbidden, but there's no promise of
backwards compatibility. We may rename, move, refactor or change those
classes at any time and with no notice.
Because backwards compatibility is so hard, it's limited to as few
classes, interfaces and annotations as possible, with as much as
possible under the internal umbrella.
In terms of your use, it looks fine, though the idea of have a
null-option-as-a-label is kind of out of date for modern browsers,
that support <optgroup> as well as <option> inside <select>, with
<optgroup> exists to provide that kind of label.
On Tue, Mar 25, 2008 at 11:51 AM, Adam Zimowski <zi...@gmail.com> wrote:
> Is the way I'm building my custom select model the "approved" Tap 5
> way? My concern is if OptionModelImpl and SelectModelImpl are still
> considered internal Tapestry classes and should be avoided? This stuff
> works fine for me and it's fairly elegant (IMHO), I just want to know
> if there is a better way.
>
> <div class="w-row">
> <div class="w-tlabel"><t:label for="article" />:</div>
> <t:select t:id="article" style="width:60%;" t:value="articleId"
> t:model="articlesModel" /></div>
>
>
> @Cached
> public SelectModel getArticlesModel() {
>
> final List<SelfHelpArticleBean> articles = getArticles();
>
> return new SelectModel() {
>
> private final SelectModel model;
>
> {
> OptionModel[] options = new OptionModel[articles.size()+1];
> options[0] = new OptionModelImpl("-- Please Select", 0);
> int index = 1;
> for(SelfHelpArticleBean article : articles) {
> String label = article.getId() +
> ": " + article.getAnchorBody();
> int value = article.getId();
> options[index++] = new OptionModelImpl(label, value);
> }
>
> model = new SelectModelImpl(options);
> }
>
> public List<OptionGroupModel> getOptionGroups() {
> return model.getOptionGroups();
> }
>
> public List<OptionModel> getOptions() {
> return model.getOptions();
> }
>
> public void visit(SelectModelVisitor aVisitor) {
> model.visit(aVisitor);
> }
>
> };
>
>
> }
>
>
> On Tue, May 8, 2007 at 12:50 AM, Bill Holloway <bi...@gmail.com> wrote:
> > I'm just hoping for a stable, best-practice, and relatively simple way
> > to set things up like Selects. Whatever you think is the best
> > approach and put in the documentation.
> >
> > Things like selects should be a snap, IMHO.
> >
> > Bill
> >
> >
> >
> > On 5/7/07, Howard Lewis Ship <hl...@gmail.com> wrote:
> > > My approach has to been to keep everything internal if possible. Thus an
> > > interface is public, the implementation is internal.
> > >
> > > If something is truly necessary, such as OptionModelImpl, there are two
> > > approaches:
> > >
> > > 1) Make the implementation class public (possibly breaking existing code
> > > that extends from the internal class) .... oh, and probably make it final as
> > > well.
> > >
> > > 2) Define a public factory service for the implementation.
> > >
> > > Right now, you can actually use the TypeCoercer as a kind of factory; if you
> > > pass in a comma-separated string and ask for an SelectModel you'll get it.
> > > Here, though, you're looking for something a little better adapted to your
> > > entity classes. However, a bare-bones implementation of OptionModel (that
> > > always returns false for isDisabled(), and null for getAttributes() ) is
> > > only a couple of lines of code.
> > >
> > > I think T4 fell into a trap of too much convenience stuff exposed as public
> > > APIs. I would rather err on the side of over-zealousness for T5. You can
> > > take internals public, but not the other way around, and once something is
> > > public, it also is (or should be) final.
> > >
> > > On 5/7/07, Bill Holloway <bi...@gmail.com> wrote:
> > > >
> > > > I've written similar code -- while remembering that OptionModelImpl is
> > > > an "internal" class that Howard, in the documentation, has admonished
> > > > us not to use.
> > > >
> > > > Community, what's the better solution?
> > > >
> > > > Bill
> > > >
> > > > On 5/7/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > Eureka!
> > > > >
> > > > > Finally got it all working. What caused the drop down to not be
> > > > > defaulting is the fact that I declared my "Brand" list in two separate
> > > > > lists... One for the ValueEncoder and one for the SelectModel. Big no
> > > > > no! An "equals" is called on the value from the SelectModel and the
> > > > > value from the ValueEncoder, so if they are initialized as separate
> > > > > objects in separate lists the framework won't notice that they are equal
> > > > > (because they would point to a different memory location). I found that
> > > > > the framework also seems to like things better if the List of Brands is
> > > > > "@Persist"ed between pages. Here's the final source code that I used to
> > > > > get it all working (Enjoy!):
> > > > >
> > > > > Brand.java (simple POJO):
> > > > >
> > > > > public class Brand {
> > > > >
> > > > > private String id;
> > > > > private String description;
> > > > >
> > > > > public Brand() {}
> > > > >
> > > > > public Brand(String id, String description) {
> > > > > this.id = id;
> > > > > this.description = description;
> > > > > }
> > > > >
> > > > > public String getId() {
> > > > > return id;
> > > > > }
> > > > >
> > > > > public String getDescription() {
> > > > > return description;
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > >
> > > > > Test.java
> > > > >
> > > > > public class Test {
> > > > >
> > > > > @Persist
> > > > > private Brand brand;
> > > > >
> > > > > @Persist
> > > > > private List<Brand> brands;
> > > > >
> > > > > public Brand getBrand() {
> > > > > return brand;
> > > > > }
> > > > >
> > > > > public void setBrand(Brand brand) {
> > > > > this.brand = brand;
> > > > > }
> > > > >
> > > > > private List<Brand> getBrands()
> > > > > {
> > > > > if(brands == null) {
> > > > > brands = new ArrayList<Brand>();
> > > > > brands.add(new Brand("1", "Brand 1"));
> > > > > brands.add(new Brand("2", "Brand 2"));
> > > > > brands.add(new Brand("3", "Brand 3"));
> > > > > brands.add(new Brand("4", "Brand 4"));
> > > > > }
> > > > >
> > > > > return brands;
> > > > > }
> > > > >
> > > > > public BrandSelectModel getBrandSelectModel() {
> > > > > return new BrandSelectModel(getBrands());
> > > > > }
> > > > >
> > > > > public BrandValueEncoder getBrandValueEncoder() {
> > > > > return new BrandValueEncoder(getBrands());
> > > > > }
> > > > >
> > > > > public class BrandValueEncoder implements ValueEncoder<Brand> {
> > > > >
> > > > > private List<Brand> brands;
> > > > >
> > > > > public BrandValueEncoder(List<Brand> brands) {
> > > > > this.brands = brands;
> > > > > }
> > > > >
> > > > > public String toClient(Brand brand) {
> > > > > return brand.getDescription();
> > > > > }
> > > > >
> > > > > public Brand toValue(String string) {
> > > > > for(Brand brand : brands) {
> > > > >
> > > > > if(brand.getDescription().equals(string)) {
> > > > > return brand;
> > > > > }
> > > > > }
> > > > > return null;
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > > public class BrandSelectModel implements SelectModel {
> > > > >
> > > > > private List<Brand> brands;
> > > > >
> > > > > public BrandSelectModel(List<Brand> brands) {
> > > > > this.brands = brands;
> > > > > }
> > > > >
> > > > > public List<OptionGroupModel> getOptionGroups() {
> > > > > return null;
> > > > > }
> > > > >
> > > > > public List<OptionModel> getOptions() {
> > > > > List<OptionModel> optionModelList = new
> > > > > ArrayList<OptionModel>();
> > > > > for(Brand brand: brands) {
> > > > > optionModelList.add(
> > > > > new OptionModelImpl(
> > > > > brand.getDescription(),
> > > > > false,
> > > > > brand,
> > > > > new String[0]
> > > > > )
> > > > > );
> > > > > }
> > > > > return optionModelList;
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > > }
> > > > >
> > > > >
> > > > > Test.html
> > > > >
> > > > > <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
> > > > > <t:form>
> > > > >
> > > > > <select t:type="select" t:id="brand"
> > > > > value="brand" model="brandSelectModel"
> > > > > encoder="brandValueEncoder"
> > > > > onchange="this.form.submit();" />
> > > > >
> > > > > <br/>
> > > > >
> > > > > <t:if test="brand">
> > > > > ${brand.description}
> > > > > </t:if>
> > > > >
> > > > > </t:form>
> > > > > </html>
> > > > >
> > > > >
> > > > > -----Original Message-----
> > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > Sent: Monday, May 07, 2007 12:17 PM
> > > > > To: Tapestry users
> > > > > Subject: Re: T5: SelectModel - a real world example
> > > > >
> > > > > Odd that you lost your value; the field is itself persistent (@Persist).
> > > > > Unless you are testing on a multi-machine cluster, you shouldn't see any
> > > > > problems along these lines!
> > > > >
> > > > > On 5/7/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > >
> > > > > > Impressive! I was injecting that value via Spring to bootstrap it.
> > > > > > Makes sense I should have removed that...
> > > > > >
> > > > > > No errors now... However, the field doesn't appear to be binding on a
> > > > >
> > > > > > form submission. The encoder and the model appear to be receiving and
> > > > >
> > > > > > returning the correct values, the brand getter and setter appear to be
> > > > >
> > > > > > getting called, and the dropdown renders correctly except that it
> > > > > > always appears to be reset to the default value...
> > > > > >
> > > > > > I apologize for being so high-maintenance. If there is a working
> > > > > > example of a T5 binding select box anywhere on the web, please point
> > > > > > me there and I will leave you alone!
> > > > > >
> > > > > > Main.html
> > > > > >
> > > > > > <t:form>
> > > > > > <select t:type="select" class="mint_font_black_background"
> > > > > > t:id="brand"
> > > > > > value="brand" model="brandSelectModel" encoder="brandValueEncoder"
> > > > > > onchange="this.form.submit();" />
> > > > > > </t:form>
> > > > > >
> > > > > >
> > > > > > Main.java
> > > > > >
> > > > > > public class Main {
> > > > > >
> > > > > > @Inject
> > > > > > @SpringBean("enterprise")
> > > > > > private Enterprise enterprise;
> > > > > >
> > > > > > @Persist
> > > > > > private Brand brand;
> > > > > >
> > > > > > public Brand getBrand() {
> > > > > > return brand;
> > > > > > }
> > > > > >
> > > > > > public void setBrand(Brand brand) {
> > > > > > this.brand = brand;
> > > > > > }
> > > > > >
> > > > > > public BrandSelectModel getBrandSelectModel() {
> > > > > > return new BrandSelectModel(enterprise.getBrands());
> > > > > > }
> > > > > >
> > > > > > public BrandValueEncoder getBrandValueEncoder() {
> > > > > > return new BrandValueEncoder(enterprise.getBrands());
> > > > > > }
> > > > > >
> > > > > > public class BrandValueEncoder implements ValueEncoder<Brand>
> > > > > > {
> > > > > >
> > > > > > private List<Brand> brands;
> > > > > >
> > > > > > public BrandValueEncoder(List<Brand> brands) {
> > > > > > this.brands = brands;
> > > > > > }
> > > > > >
> > > > > > public String toClient(Brand brand) {
> > > > > > return brand.getDescription();
> > > > > > }
> > > > > >
> > > > > > public Brand toValue(String string) {
> > > > > > for(Brand brand : brands) {
> > > > > >
> > > > > > if(brand.getDescription().equals(string)) {
> > > > > > return brand;
> > > > > > }
> > > > > > }
> > > > > > return null;
> > > > > > }
> > > > > >
> > > > > > }
> > > > > >
> > > > > > public class BrandSelectModel implements SelectModel {
> > > > > >
> > > > > > private List<Brand> brands;
> > > > > >
> > > > > > public BrandSelectModel(List<Brand> brands) {
> > > > > > this.brands = brands;
> > > > > > }
> > > > > >
> > > > > > public List<OptionGroupModel> getOptionGroups() {
> > > > > > return null;
> > > > > > }
> > > > > >
> > > > > > public List<OptionModel> getOptions() {
> > > > > > List<OptionModel> optionModelList =
> > > > > > new ArrayList<OptionModel>();
> > > > > > for(Brand brand: brands) {
> > > > > > optionModelList.add(
> > > > > > new OptionModelImpl(
> > > > > > brand.getDescription(),
> > > > > > false,
> > > > > > brand,
> > > > > > new String[0]
> > > > > > )
> > > > > > );
> > > > > > }
> > > > > > return optionModelList;
> > > > > > }
> > > > > >
> > > > > > }
> > > > > >
> > > > > > }
> > > > > >
> > > > > >
> > > > > >
> > > > > > -----Original Message-----
> > > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > > Sent: Saturday, May 05, 2007 9:45 PM
> > > > > > To: Tapestry users
> > > > > > Subject: Re: T5: SelectModel - a real world example
> > > > > >
> > > > > > What annotations are on the brand field of your Main class? Something
> > > > >
> > > > > > has changes that field to be read-only, which is usually a sign that a
> > > > >
> > > > > > value was injected.
> > > > > >
> > > > > > On 5/4/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > > >
> > > > > > > Still getting unintuitive errors... I've added the ValueEncoder and
> > > > > > > now when I submit the form I get the following stack trace (and yes
> > > > > > > the "Main" component has a setBrand(Brand) method, which from the
> > > > > > > root
> > > > > >
> > > > > > > cause exception seems to be the cause of the problem?):
> > > > > > >
> > > > > > > [ERROR] RequestExceptionHandler Processing of request failed with
> > > > > > > uncaught exception:
> > > > > > > org.apache.tapestry.ioc.internal.util.TapestryException: Failure
> > > > > > > writing parameter value of component com.foo.pages.Main:brand: Field
> > > > >
> > > > > > > com.foo.pages.Main.brand is read-only. [at
> > > > > > > context:WEB-INF/Main.html, line 89, column 278]
> > > > > > > java.lang.RuntimeException:
> > > > > > > org.apache.tapestry.ioc.internal.util.TapestryException: Failure
> > > > > > > writing parameter value of component com.foo.
> > > > > > > pages.Main:brand: Field com.foo.pages.Main.brand is read-only. [at
> > > > > > > context:WEB-INF/Main.html, line 89, column 278]
> > > > > > > at
> > > > > > > org.apache.tapestry.corelib.components.Form.onAction(Form.java:356)
> > > > > > > at
> > > > > > >
> > > > > org.apache.tapestry.corelib.components.Form.handleComponentEvent(Form.
> > > > > > > ja
> > > > > > > va)
> > > > > > > at
> > > > > > > org.apache.tapestry.internal.structure.ComponentPageElementImpl.hand
> > > > > > > le
> > > > > > > Ev
> > > > > > > ent(ComponentPageElementImpl.java:903)
> > > > > > > at
> > > > > > > org.apache.tapestry.internal.structure.ComponentPageElementImpl.trig
> > > > > > > ge
> > > > > > > rE
> > > > > > > vent(ComponentPageElementImpl.java:1002)
> > > > > > > at
> > > > > > > org.apache.tapestry.internal.services.ActionLinkHandlerImpl.handle(A
> > > > > > > ct
> > > > > > > io
> > > > > > > nLinkHandlerImpl.java:100)
> > > > > > > at
> > > > > > > org.apache.tapestry.internal.services.ActionLinkHandlerImpl.handle(A
> > > > > > > ct
> > > > > > > io
> > > > > > > nLinkHandlerImpl.java:53)
> > > > > > > at
> > > > > > > $ActionLinkHandler_11258c2d07d.handle($ActionLinkHandler_11258c2d07d
> > > > > > > .j
> > > > > > > av
> > > > > > > a)
> > > > > > > at
> > > > > > > org.apache.tapestry.internal.services.ComponentActionDispatcher.disp
> > > > > > > at
> > > > > > > ch
> > > > > > > (ComponentActionDispatcher.java:115)
> > > > > > > ... 40 more
> > > > > > > Caused by: org.apache.tapestry.ioc.internal.util.TapestryException:
> > > > > > > Failure writing parameter value of component
> > > > > com.foo.pages.Main:brand:
> > > > > > > Field com.foo.pages.Main.brand is read-only. [at
> > > > > > > context:WEB-INF/Main.html, line 89, column 278]
> > > > > > > at
> > > > > > >
> > > > > org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.
> > > > > > > wr
> > > > > > > iteParameter(InternalComponentResourcesImpl.java:223)
> > > > > > > at
> > > > > > > org.apache.tapestry.corelib.components.Select._$update_parameter_val
> > > > > > > ue
> > > > > > > _0
> > > > > > > (Select.java)
> > > > > > > at
> > > > > > > org.apache.tapestry.corelib.components.Select.processSubmission(Sele
> > > > > > > ct
> > > > > > > .j
> > > > > > > ava:238)
> > > > > > > at
> > > > > > > org.apache.tapestry.corelib.base.AbstractField.processSubmission(Abs
> > > > > > > tr
> > > > > > > ac
> > > > > > > tField.java:210)
> > > > > > > at
> > > > > > >
> > > > > >
> > > > > org.apache.tapestry.corelib.base.AbstractField.access$100(AbstractField.
> > > > > > > java:47)
> > > > > > > at
> > > > > > > org.apache.tapestry.corelib.base.AbstractField$ProcessSubmissionActi
> > > > > > > on
> > > > > > > .e
> > > > > > > xecute(AbstractField.java:116)
> > > > > > > at
> > > > > > > org.apache.tapestry.corelib.base.AbstractField$ProcessSubmissionActi
> > > > > > > on
> > > > > > > .e
> > > > > > > xecute(AbstractField.java:110)
> > > > > > > at
> > > > > > > org.apache.tapestry.corelib.components.Form.onAction(Form.java:347)
> > > > > > > ... 40 more
> > > > > > > Caused by: org.apache.tapestry.ioc.internal.util.TapestryException:
> > > > > > > Field com.foo.pages.Main.brand is read-only. [at
> > > > > context:WEB-INF/Main.
> > > > > > > html, line 89, column 278]
> > > > > > > at
> > > > > > > org.apache.tapestry.internal.bindings.PropBinding.set(PropBinding.ja
> > > > > > > va
> > > > > > > :7
> > > > > > > 1)
> > > > > > > at
> > > > > > >
> > > > > org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.
> > > > > > > wr
> > > > > > > iteParameter(InternalComponentResourcesImpl.java:219)
> > > > > > > ... 47 more
> > > > > > > Caused by: java.lang.RuntimeException: Field
> > > > > > > com.foo.pages.Main.brand is read-only.
> > > > > > > at com.foo.pages.Main._$write_brand(Main.java)
> > > > > > > at com.foo.pages.Main.setBrand(Main.java:92)
> > > > > > > at
> > > > > > > $PropertyConduit_11258c2d0a9.set($PropertyConduit_11258c2d0a9.java)
> > > > > > > at
> > > > > > > org.apache.tapestry.internal.bindings.PropBinding.set(PropBinding.ja
> > > > > > > va
> > > > > > > :6
> > > > > > > 7)
> > > > > > > ... 48 more
> > > > > > >
> > > > > > >
> > > > > > >
> > > > > > > -----Original Message-----
> > > > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > > > Sent: Friday, May 04, 2007 2:32 PM
> > > > > > > To: Tapestry users
> > > > > > > Subject: Re: T5: SelectModel - a real world example
> > > > > > >
> > > > > > > In your OptionModel, the label is the Brand description, and the
> > > > > > > value
> > > > > >
> > > > > > > is the Brand itself.
> > > > > > >
> > > > > > > You then supply a ValueEncoder that converts between Brands and
> > > > > > > brand ids (as strings, for the client side). If Brand is an entity
> > > > > > > object, then it may be necessary to have the ValueEncoder talk to
> > > > > > > the database
> > > > > >
> > > > > > > or session store.
> > > > > > >
> > > > > > > On 5/4/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > > > >
> > > > > > > > Thanks for the reply Howard.
> > > > > > > >
> > > > > > > > >> The Select component doesn't know how to create a client-side
> > > > > > > > representation of a Brand (it doesn't magically know to use the
> > > > > id).
> > > > > > > >
> > > > > > > > So, then... I guess my question would be... what is the
> > > > > > > > BrandSelectModel for? In that object, I'm essentially mapping a
> > > > > > > > Brand's "description" to the Brand object.
> > > > > > > >
> > > > > > > > Just curious what your thoughts are on that...
> > > > > > > >
> > > > > > > >
> > > > > > > > -----Original Message-----
> > > > > > > > From: Howard Lewis Ship [mailto:hlship@gmail.com]
> > > > > > > > Sent: Friday, May 04, 2007 1:42 PM
> > > > > > > > To: Tapestry users
> > > > > > > > Subject: Re: T5: SelectModel - a real world example
> > > > > > > >
> > > > > > > > In the simplest case, T5 thinks that the options in the drop down
> > > > > > > > list
> > > > > > >
> > > > > > > > are all strings.
> > > > > > > >
> > > > > > > > In your case, they are Brands. The Select component doesn't know
> > > > > > > > how to create a client-side representation of a Brand (it doesn't
> > > > > > > > magically know to use the id).
> > > > > > > >
> > > > > > > > You must provide a ValueEncoder that can convert between Brands
> > > > > > > > and client-side string values. This is the encoder parameter of
> > > > > > > > the Select component.
> > > > > > > >
> > > > > > > >
> > > > > > > > On 5/4/07, Joel Wiegman <Jo...@btservices.com> wrote:
> > > > > > > > >
> > > > > > > > > Not to be harsh, but I don't think I've ever written a select
> > > > > > > > > box with
> > > > > > > >
> > > > > > > > > constant values (Enum). Seems like even Male/Female drop downs
> > > > > > > > > need
> > > > > > >
> > > > > > > > > to be data-driven now-a-days. :->
> > > > > > > > >
> > > > > > > > > I've started to stub out a very simple "real world example" of a
> > > > >
> > > > > > > > > select component in T5, but it doesn't appear to be as simple as
> > > > >
> > > > > > > > > I
> > > > > >
> > > > > > > > > thought it would be.
> > > > > > > > >
> > > > > > > > > A shiny nickel to anyone that can spot the flaw, because I sure
> > > > > > > > can't...
> > > > > > > > > I'm new to Tapestry in general so I could be missing something
> > > > > > > > > really mundane here, but seems like it should work in my mind.
> > > > > > > > >
> > > > > > > > > Here are the players:
> > > > > > > > >
> > > > > > > > > << THE ERROR >>
> > > > > > > > >
> > > > > > > > > [ERROR] DefaultRequestExceptionHandler Processing of request
> > > > > > > > > failed with uncaught exception: com.foo.data.Brand cannot be
> > > > > > > > > cast to java.lang.String
> > > > > > > > > java.lang.ClassCastException: com.foo.data.Brand cannot be cast
> > > > > > > > > to
> > > > > >
> > > > > > > > > java.lang.String
> > > > > > > > > at
> > > > > > > > >
> > > > > > > > org.apache.tapestry.corelib.components.Select$1.toClient(Select.ja
> > > > > > > > va
> > > > > > > > :6
> > > > > > > > 2)
> > > > > > > > > at
> > > > > > > > >
> > > > > org.apache.tapestry.corelib.components.Select.writeOptions(Select.
> > > > > > > > > ja
> > > > > > > > > va
> > > > > > > > > :1
> > > > > > > > > 94)
> > > > > > > > > at
> > > > > > > > >
> > > > > > > org.apache.tapestry.corelib.components.Select.options(Select.java:16
> > > > > > > 9)
> > > > > > > > > at
> > > > > > > > > org.apache.tapestry.corelib.components.Select.beforeRenderTempla
> > > > > > > > > te
> > > > > > > > > (S
> > > > > > > > > el
> > > > > > > > > ec
> > > > > > > > > t.java)
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > << Main.html (abridged) >>
> > > > > > > > >
> > > > > > > > > <t:form>
> > > > > > > > > <select t:type="select" t:id="brand" value="brand"
> > > > > > > > > model="brandSelectModel"/>
> > > > > > > > > </t:form>
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > << Main.java (abridged) >>
> > > > > > > > >
> > > > > > > > > package com.foo.pages;
> > > > > > > > >
> > > > > > > > > import com.foo.data.Brand;
> > > > > > > > >
> > > > > > > > > public class Main {
> > > > > > > > >
> > > > > > > > > private Brand brand;
> > > > > > > > >
> > > > > > > > > public Brand getBrand() {
> > > > > > > > > return brand;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public void setBrand(Brand brand) {
> > > > > > > > > this.brand = brand;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public BrandSelectModel getBrandSelectModel() {
> > > > > > > > > return new BrandSelectModel(getBrands());
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public List<Brand> getBrands() {
> > > > > > > > > List<Brand> brands = new ArrayList<Brand>();
> > > > > > > > > brands.add(new Brand("1", "Brand 1"));
> > > > > > > > > brands.add(new Brand("2", "Brand 2"));
> > > > > > > > > brands.add(new Brand("3", "Brand 3"));
> > > > > > > > > return brands;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > << Brand.java (abridged) >>
> > > > > > > > >
> > > > > > > > > package com.foo.data;
> > > > > > > > >
> > > > > > > > > public class Brand {
> > > > > > > > >
> > > > > > > > > private String id;
> > > > > > > > > private String description;
> > > > > > > > >
> > > > > > > > > public Brand() {}
> > > > > > > > >
> > > > > > > > > public Brand(String id, String description) {
> > > > > > > > > this.id = id;
> > > > > > > > > this.description = description;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public String getId() {
> > > > > > > > > return id;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public String getDescription() {
> > > > > > > > > return description;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > << BrandSelectModel.java >>
> > > > > > > > >
> > > > > > > > > package com.foo.uisupport;
> > > > > > > > >
> > > > > > > > > import com.foo.data.Brand;
> > > > > > > > >
> > > > > > > > > public class BrandSelectModel implements SelectModel {
> > > > > > > > >
> > > > > > > > > private List<Brand> brands;
> > > > > > > > >
> > > > > > > > > public BrandSelectModel(List<Brand> brands) {
> > > > > > > > > this.brands = brands;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public List<OptionGroupModel> getOptionGroups() {
> > > > > > > > > return null;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > public List<OptionModel> getOptions() {
> > > > > > > > > List<OptionModel> optionModelList = new
> > > > > > > > > ArrayList<OptionModel>();
> > > > > > > > > for(Brand brand: brands) {
> > > > > > > > > optionModelList.add(new
> > > > > > > > > OptionModelImpl(brand.getDescription(), false, brand, new
> > > > > > > String[0]));
> > > > > > > > > }
> > > > > > > > > return optionModelList;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > ----------------------------------------------------------------
> > > > > > > > > --
> > > > > > > > > --
> > > > > > > > > - To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > > > > > >
> > > > > > > > >
> > > > > > > >
> > > > > > > >
> > > > > > > > --
> > > > > > > > Howard M. Lewis Ship
> > > > > > > > TWD Consulting, Inc.
> > > > > > > > Independent J2EE / Open-Source Java Consultant Creator and PMC
> > > > > > > > Chair, Apache Tapestry Creator, Apache HiveMind
> > > > > > > >
> > > > > > > > Professional Tapestry training, mentoring, support and project
> > > > > work.
> > > > > > > > http://howardlewisship.com
> > > > > > > >
> > > > > > > > ------------------------------------------------------------------
> > > > > > > > --
> > > > > > > > - To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > > > > >
> > > > > > > >
> > > > > > >
> > > > > > >
> > > > > > > --
> > > > > > > Howard M. Lewis Ship
> > > > > > > TWD Consulting, Inc.
> > > > > > > Independent J2EE / Open-Source Java Consultant Creator and PMC
> > > > > > > Chair, Apache Tapestry Creator, Apache HiveMind
> > > > > > >
> > > > > > > Professional Tapestry training, mentoring, support and project work.
> > > > > > > http://howardlewisship.com
> > > > > > >
> > > > > > > --------------------------------------------------------------------
> > > > > > > - To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > > > >
> > > > > > >
> > > > > >
> > > > > >
> > > > > > --
> > > > > > Howard M. Lewis Ship
> > > > > > TWD Consulting, Inc.
> > > > > > Independent J2EE / Open-Source Java Consultant Creator and PMC Chair,
> > > > > > Apache Tapestry Creator, Apache HiveMind
> > > > > >
> > > > > > Professional Tapestry training, mentoring, support and project work.
> > > > > > http://howardlewisship.com
> > > > > >
> > > > > > ---------------------------------------------------------------------
> > > > > > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > > >
> > > > > >
> > > > >
> > > > >
> > > > > --
> > > > > Howard M. Lewis Ship
> > > > > TWD Consulting, Inc.
> > > > > Independent J2EE / Open-Source Java Consultant Creator and PMC Chair,
> > > > > Apache Tapestry Creator, Apache HiveMind
> > > > >
> > > > > Professional Tapestry training, mentoring, support and project work.
> > > > > http://howardlewisship.com
> > > > >
> > > > > ---------------------------------------------------------------------
> > > > > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > > >
> > > > >
> > > >
> > > >
> > > > --
> > > > "The future is here. It's just not evenly distributed yet."
> > > >
> > > > -- Traditional
> > > >
> > > > ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > > > For additional commands, e-mail: users-help@tapestry.apache.org
> > > >
> > > >
> > >
> > >
> > > --
> > > Howard M. Lewis Ship
> > > TWD Consulting, Inc.
> > > Independent J2EE / Open-Source Java Consultant
> > > Creator and PMC Chair, Apache Tapestry
> > > Creator, Apache HiveMind
> > >
> > > Professional Tapestry training, mentoring, support
> > > and project work. http://howardlewisship.com
> > >
> >
> >
> > --
> >
> >
> > "The future is here. It's just not evenly distributed yet."
> >
> > -- Traditional
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > For additional commands, e-mail: users-help@tapestry.apache.org
> >
> >
>
> ---------------------------------------------------------------------
>
>
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
--
Howard M. Lewis Ship
Creator Apache Tapestry and Apache HiveMind
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org