The ValueEncoder makes it so that you can store the values used in the loop in the form. When the form is submitted the ValueEncoder is used to turn the values stored in the form back into objects. The checkbox component calls the setter on the restored object. Your ValueEncoder needs to be able to turn the string that you sent to the browser back into an object. You can do that by creating a map of string to object when the form is submitted (in onPrepareForSubmit()) and then use the map in your ValueEncoder. Or you could just iterate over the list you are creating with getFormFieldsToCreate()...
On Tue, Apr 13, 2010 at 9:07 AM, jaques robert <mondes_englou...@yahoo.fr> wrote: > Thanks for that code. With this value encoder how can I see in my code that > the checkboxes <input t:type="checkbox" t:id="checked" > value="documentField.selected"/> are checked or unchecked ? > > The code I'm using is : > public List<String> getFormFieldsToCreate() { > if (_formFieldsToCreate == null) { > _formFieldsToCreate = new ArrayList<String>(); > } > System.out.println("getFormFieldsToCreate()"); > for (ExportProcessType ept : _processTypes) { > System.out.println("\tept : " + ept); > for (ExportDocumentType edt : ept.getDocumentTypes()) { > System.out.println("\t\tedt : " + edt); > for (ExportDocumentField edf : edt.getDocumentFields()) { > System.out.println("\t\t\tedf : " + edf); > if (edf.getSelected()) { > System.out.println("\t\t\t\tin > getFormFieldsToCreate() " + edf.getDocumentFieldDN()); > _formFieldsToCreate.add(edf.getDocumentFieldDN()); > } > } > } > } > > return _formFieldsToCreate; > } > > private Object onSuccess() { > // call database update > > System.out.println("writing for " + _profilName +", " + _language + > ", " + getFormFieldsToCreate()); > getExportService().modifyExportProfil(_profilName, _language, > getFormFieldsToCreate()); > > //return this; > return null; > } > > > Regards, > Mondes. > --- En date de : Lun 12.4.10, Josh Canfield <joshcanfi...@gmail.com> a écrit : > > De: Josh Canfield <joshcanfi...@gmail.com> > Objet: Re: simple case for checkboxes & T5 > À: "Tapestry users" <users@tapestry.apache.org> > Date: Lundi 12 avril 2010, 23h13 > >> <t:Loop t:source="documentType.documentFields" t:value="documentField" >> formState="values"> > > When you tell the loop to store the values it literally converts them > to strings and stores them in a field in the form. You need to provide > a ValueEncoder to the loop that can convert the object to a string for > storage on the client, and interpret that string when the loop is > trying to restore the value. If you don't provide a proper > ValueEncoder then what gets stored is the toString provided of the > object (which is most likely not what you want) and then when you post > the form the loop component chokes trying to turn that string into > your object. In the case of a database object this usually entails > storing the id and then querying it when the form is submitted. > > Here is an example of a ValueEncoder that you could use: > > // Lookup fields by their fieldDN > private Map<String, DocumentField> _dnToField; > > void onPrepareForSubmit() { > // load your objects > _dnToField = new HashMap<String, DocumentField>(); > // populate _dnToField from your data > } > > public ValueEncoder<DocumentField> getDocumentFieldValueEncoder() { > return new ValueEncoder<DocumentField>() { > > public String toClient(DocumentField value) { > return value.getDocumentFieldDN(); > } > > // Depends on the _dnToField being populated with all the fields. > public DocumentField toValue(String clientValue) { > DocumentField field = _dnToField.get(clientValue); > if (field != null) { > return field; > } > throw new RuntimeException("Need to handle posts of > fieldDNs that no longer exist"); > } > }; > } > > <t:Loop t:source="documentType.documentFields" t:value="documentField" > encoder="documentFieldValueEncoder" > formState="values"> > > > Josh > > On Mon, Apr 12, 2010 at 8:18 AM, jaques robert > <mondes_englou...@yahoo.fr> wrote: >> Thanks a lot for your code, I'm going to try it. >> >> However, if I take the standard component of T5 : >> <t:Loop t:source="documentType.documentFields" t:value="documentField" >> formState="values"> >> <div >> id="div_docfield_${documentField.documentFieldDN}" style="display: block"> >> <table style="text-align: left; >> width: 1592px; margin-left: 50px;" border="1" cellpadding="2" >> cellspacing="2"> >> <tbody> >> <tr> >> <td style="width: 29px;"> >> <input >> t:type="checkbox" t:id="checked" value="documentField.selected"/> >> </td> >> <td style="width: 527px;"> >> >> ${documentField.documentField} (${documentField.documentFieldDN}) >> </td> >> <td style="width: 990px;"> >> >> <a href="#" >> t:type="pagelink" t:page="DisplaySampleValues" >> t:context="documentField.documentFieldDN">Exemples</a> >> </td> >> </tr> >> </tbody> >> </table> >> </div> >> </t:Loop> >> >> I dont understand that the tick of checkbox are not put inside my new >> property documentField.selected. Is this component only for display ? >> >> --- En date de : Sam 10.4.10, Josh Canfield <joshcanfi...@gmail.com> a >> écrit : >> >> De: Josh Canfield <joshcanfi...@gmail.com> >> Objet: Re: simple case for checkboxes & T5 >> À: "Tapestry users" <users@tapestry.apache.org> >> Date: Samedi 10 avril 2010, 0h51 >> >> Hi. >> >> Here is a solution using a patch of the standard checkbox component >> that accepts any Object that can be ValueEncoder encoded. I created >> stand-in objects and make the assumption that documentFieldDN is >> unique and can be used in a set of all documentFieldDN. >> >> You could persist the set as query parameters, or in the browser >> cookie or whatever but I'm just sticking the set into the session. >> >> Enjoy! >> >> Josh >> >> >> ******************************************** >> ********** Checkbox.java **************** >> ******************************************** >> >> package com.joshcanfield.tapestry.common.components; >> >> import org.apache.tapestry5.ComponentResources; >> import org.apache.tapestry5.MarkupWriter; >> import org.apache.tapestry5.ValidationTracker; >> import org.apache.tapestry5.ValueEncoder; >> import org.apache.tapestry5.annotations.*; >> import org.apache.tapestry5.corelib.base.AbstractField; >> import org.apache.tapestry5.corelib.mixins.RenderDisabled; >> import org.apache.tapestry5.ioc.annotations.Inject; >> import org.apache.tapestry5.services.ComponentDefaultProvider; >> import org.apache.tapestry5.services.Request; >> >> /** >> * A Checkbox component is simply a <input type="checkbox">. >> * >> */ >> public class Checkbox extends AbstractField { >> private static final String NULL_TOKEN = "::null::"; >> >> /** >> * The value to be read or updated. If not bound, the Checkbox >> will attempt to edit a property of its container >> * whose name matches the component's id. >> */ >> @Parameter(required = true, autoconnect = true) >> private Object value; >> >> @Parameter(autoconnect = true) >> private boolean checked; >> >> /** >> * Value encoder for the value, usually determined automatically >> from the type of the property bound to the value >> * parameter. >> */ >> @Parameter(required = true) >> private ValueEncoder<Object> encoder; >> >> @Inject >> private Request request; >> >> @SuppressWarnings("unused") >> @Mixin >> private RenderDisabled renderDisabled; >> >> @Inject >> private ComponentResources resources; >> >> @Inject >> private ComponentDefaultProvider defaultProvider; >> @Environmental >> private ValidationTracker tracker; >> >> ValueEncoder defaultEncoder() { >> return defaultProvider.defaultValueEncoder("value", resources); >> } >> >> @BeginRender >> void begin(MarkupWriter writer) { >> final boolean isBoolean = value != null && value instanceof Boolean; >> // Available only when there is an error in the form >> final String asSubmitted = tracker.getInput(this); >> >> boolean isChecked = false; >> >> if (asSubmitted != null) { >> // This is true when there is a form error. >> isChecked = isBoolean ? Boolean.parseBoolean(asSubmitted) >> : !asSubmitted.equals(NULL_TOKEN); >> } else if (resources.isBound("checked")) { >> isChecked = checked; >> } else if (isBoolean) { >> isChecked = (Boolean) value; >> } >> >> writer.element("input", "type", "checkbox", >> "name", getControlName(), >> "id", getClientId(), >> // For non-boolean values we always grab the value >> from the bound parameter because >> // we can't reconstitute it from a form post >> "value", isBoolean ? null : encoder.toClient(value), >> "checked", isChecked ? "checked" : null); >> >> resources.renderInformalParameters(writer); >> >> decorateInsideField(); >> } >> >> @AfterRender >> void after(MarkupWriter writer) { >> writer.end(); // input >> } >> >> @Override >> protected void processSubmission(String elementName) { >> // if the value wasn't submitted then it will be null >> final String postedValue = request.getParameter(elementName); >> >> value = encoder.toValue(postedValue); >> >> // Stick a null token in there so we know when there was an >> error in the form and can skip other checks. >> tracker.recordInput(this, postedValue == null ? NULL_TOKEN : >> postedValue); >> } >> } >> >> ******************************************** >> ********** CheckboxTest.java *********** >> ******************************************** >> >> package usr.joshcan.tapestry.pages; >> >> import com.joshcanfield.tapestry.common.components.Checkbox; >> import org.apache.tapestry5.annotations.Component; >> import org.apache.tapestry5.annotations.PageLoaded; >> import org.apache.tapestry5.annotations.Persist; >> import org.apache.tapestry5.annotations.Property; >> >> import java.util.ArrayList; >> import java.util.HashSet; >> import java.util.List; >> import java.util.Set; >> >> /** >> * User: joshcanfield >> * Date: Apr 9, 2010 >> */ >> public class CheckboxTest { >> >> private List<ProcessType> _processTypes; >> >> >> @Property >> private ProcessType _processType; >> >> @Property >> private DocumentType _documentType; >> >> @Property >> private DocumentField _documentField; >> >> @Component >> private Checkbox _checkbox; >> >> @Persist >> private Set<String> _checked; >> >> /* >> * Page Life cycle methods >> */ >> @PageLoaded >> void createObjects() { >> // Runs once when the page >> _processTypes = new ArrayList<ProcessType>(); >> >> >> for (String ptName : new String[]{"processType One", >> "processType Two", "processType Three"}) { >> >> List<DocumentType> docTypes = new ArrayList<DocumentType>(); >> for (String dtName : new String[]{"dt1", "dt2", "dt3"}) { >> List<DocumentField> fields = new ArrayList<DocumentField>(); >> for (String documentField : new String[]{"df1", "df2", >> "df3"}) { >> // creating a documentFieldDN that uniquely identifies >> it. >> final String documentFieldDN = >> String.format("%s.%s.%s", ptName, dtName, documentField); >> fields.add(new DocumentField(documentFieldDN)); >> } >> >> docTypes.add(new DocumentType(dtName, fields)); >> } >> _processTypes.add(new ProcessType(ptName, docTypes)); >> } >> } >> >> /** >> * Always start with a fresh set since the new values are being posted >> */ >> void onPrepareForSubmit() { >> _checked = new HashSet<String>(); >> } >> >> /** >> * When rendering for the first time there won't be a _checked set >> in the session. >> */ >> void onPrepareForRender() { >> if (_checked == null) _checked = new HashSet<String>(); >> } >> >> public List<ProcessType> getProcessTypes() { >> return _processTypes; >> } >> >> public String getDocumentFieldDN() { >> // Returns the current loop value >> return _documentField.getDocumentFieldDN(); >> } >> >> public void setDocumentFieldDN(String value) { >> // unchecked boxes are set as null, we just ignore the null values. >> if (value != null) _checked.add(value); >> } >> >> public boolean getDocumentFieldIsChecked() { >> return _checked.contains(_documentField.getDocumentFieldDN()); >> } >> >> /* >> * Faked up classes >> */ >> >> public class ProcessType { >> private List<DocumentType> _documentTypes; >> private String _name; >> >> public ProcessType(String name, List<DocumentType> documentTypes) { >> _documentTypes = documentTypes; >> _name = name; >> } >> >> public String getName() { >> return _name; >> } >> >> public void setName(String name) { >> _name = name; >> } >> >> public List<DocumentType> getDocumentTypes() { >> return _documentTypes; >> } >> >> public void setDocumentTypes(List<DocumentType> documentTypes) { >> _documentTypes = documentTypes; >> } >> } >> >> public class DocumentType { >> private List<DocumentField> _documentFields; >> private String _name; >> >> public DocumentType(String name, List<DocumentField> documentFields) >> { >> _name = name; >> _documentFields = documentFields; >> } >> >> public String getName() { >> return _name; >> } >> >> public void setName(String name) { >> _name = name; >> } >> >> public List<DocumentField> getDocumentFields() { >> return _documentFields; >> } >> >> public void setDocumentFields(List<DocumentField> documentFields) { >> _documentFields = documentFields; >> } >> } >> >> public class DocumentField { >> private String _documentFieldDN; >> >> public DocumentField(String documentFieldDN) { >> _documentFieldDN = documentFieldDN; >> } >> >> public String getDocumentFieldDN() { >> return _documentFieldDN; >> } >> >> public void setDocumentFieldDN(String documentFieldDN) { >> _documentFieldDN = documentFieldDN; >> } >> } >> } >> >> ******************************************** >> ********** CheckboxTest.tml ************ >> ******************************************** >> >> <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> >> >> <head><title>Checkbox test</title></head> >> <body> >> <t:form> >> <ul> >> <t:loop t:source="processTypes" t:value="processType" >> formState="none"> >> <li>${processType.name}</li> >> <ul> >> >> <t:loop t:source="processType.documentTypes" >> t:value="documentType" formState="none"> >> <li>${documentType.name}</li> >> <ul> >> <t:loop t:source="documentType.documentFields" >> t:value="documentField" formState="none"> >> >> <li> >> <t:checkbox t:id="checkbox" >> t:value="documentFieldDN" >> >> t:checked="documentFieldIsChecked"/> >> <label >> for="${documentFieldDN}">${documentField.documentFieldDN}</label> >> </li> >> </t:loop> >> </ul> >> </t:loop> >> </ul> >> >> </t:loop> >> </ul> >> <t:submit/> >> </t:form> >> >> </body> >> </html> >> >> Josh >> >> On Fri, Apr 9, 2010 at 3:54 AM, jaques robert <mondes_englou...@yahoo.fr> >> wrote: >>> Hello, >>> >>> >>> I've got some problemes with checkbox & T5 for a while. I'd just like to >>> display a page which could contains some checkbox, then submit this page in >>> order to treat the various item corresponding to the ticked checkbox then >>> redirect to the same page with the same checkbox ticked. It is simple with >>> JSP however seems complicated to me to realize with T5 >>> >>> >>> <t:Loop t:source="processTypes" t:value="processType" >>> formState="none"> >>> >>> <t:Loop t:source="processType.documentTypes" >>> t:value="documentType" formState="none"> >>> >>> <t:Loop t:source="documentType.documentFields" >>> t:value="documentField" formState="values"> >>> >>> <t:if >>> test="documentField.checked"> >>> >>> <input >>> type="checkbox" name="selectedDocumentFields" >>> value="${documentField.documentFieldDN}" checked="checked"/> >>> >>> </t:if> >>> >>> <!-- <input t : >>> type="checkbox" t : id="checked" value="documentField.documentFieldDN" >>> />--> >>> >>> ... >>> >>> >>> >>> Howard Lewis Ship advise to use the http request without using t5 component >>> in this cas. That was I've done. However for the display when returning to >>> this page after submission documentField.checked is always to false >>> >>> Perhaps I'm missing something moreover I think I'm making a "usine à gaz". >>> >>> >>> On the onActivate() I've got : >>> >>> _exportNameForModifcation = exportNameForModification; >>> >>> System.out.println("_exportNameForModifcation : " + >>> _exportNameForModifcation); >>> >>> documentFieldAlreadyTicked = >>> getExportService().getDocumentFields(exportNameForModification); >>> >>> >>> >>> HttpServletRequest req = requestGlobals.getHTTPServletRequest(); >>> >>> List<String> selectedDocumentFields = new >>> LinkedList<String>(); >>> >>> >>> >>> on the onSuccess() : >>> >>> HttpServletRequest req = requestGlobals.getHTTPServletRequest(); >>> >>> String[] exportToCreate = >>> req.getParameterValues("selectedDocumentFields"); >>> >>> >>> >>> System.out.println("exportToCreate : " + exportToCreate); >>> >>> >>> _formFieldsToCreate = Arrays.asList(exportToCreate); >>> >>> >>> >>> getExportService().modifyExportProfil(_profilName, _language, >>> _formFieldsToCreate); >>> >>> >>> >>> //return this; >>> >>> return null; >>> >>> >>> on the getDocumentField() >>> >>> >>> >>> public ExportDocumentField getDocumentField() { >>> >>> System.out.println("_documentField : " + _documentField); >>> >>> if (documentFieldAlreadyTicked.contains(_documentField)) { >>> >>> _documentField.setChecked("true"); >>> >>> System.out.println(documentFieldAlreadyTicked + " contains >>> " + _documentField); >>> >>> } >>> >>> else { >>> >>> System.out.println(documentFieldAlreadyTicked + " does not >>> contains " + _documentField); >>> >>> _documentField.setChecked(null); >>> >>> } >>> >>> >>> >>> return _documentField; >>> >>> } >>> >>> >>> It sux cause getDocumentField() is called much more times than the item >>> displayed. Is it the good way to go ? >>> >>> >>> If I use a t:checkbox component I see that there isn't a selected property >>> as in T3 for knowing which one is >>> selected.http://tapestry.apache.org/tapestry5/tapestry-core/ref/org/apache/tapestry5/corelib/components/Checkbox.html) >>> >>> >>> Can you help me resolve this case ? >>> >>> Regards, >>> Mondes. >>> >>> >>> >>> >> >> >> >> -- >> -- >> http://www.bodylabgym.com - a private, by appointment only, one-on-one >> health and fitness facility. >> -- >> http://www.ectransition.com - Quality Electronic Cigarettes at a >> reasonable price! >> -- >> TheDailyTube.com. Sign up and get the best new videos on the internet >> delivered fresh to your inbox. >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org >> For additional commands, e-mail: users-h...@tapestry.apache.org >> >> >> >> >> > > > > -- > -- > http://www.bodylabgym.com - a private, by appointment only, one-on-one > health and fitness facility. > -- > http://www.ectransition.com - Quality Electronic Cigarettes at a > reasonable price! > -- > TheDailyTube.com. Sign up and get the best new videos on the internet > delivered fresh to your inbox. > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org > For additional commands, e-mail: users-h...@tapestry.apache.org > > > > > -- -- http://www.bodylabgym.com - a private, by appointment only, one-on-one health and fitness facility. -- http://www.ectransition.com - Quality Electronic Cigarettes at a reasonable price! -- TheDailyTube.com. Sign up and get the best new videos on the internet delivered fresh to your inbox. --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org