Hi @all, i try to use an AjaxFormLoop to implement a dynamic filter component. U can interactively add or remove new single filter to a filter form.
Every single filter row has a select to specify the column. This select replace the input field for the filter expression depending on the column type with an ajax zone update. If i try to place a DateField in this scenario i got an parse error after i click on the calendar icon of the added DateField, see here http://postimg.org/image/c57601flj/ It looks like the DateField.js use the hidden "t:formdata input" of the DateField for reading and writing, which is as far as i understood wrong. Any ideas, how i can fix this issue??? Kind regards simple code to (hopefully) reproduce the error: import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.tapestry5.Block; import org.apache.tapestry5.ValueEncoder; import org.apache.tapestry5.annotations.InjectComponent; import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.corelib.components.Zone; import org.apache.tapestry5.ioc.annotations.Inject; import org.apache.tapestry5.services.Request; import org.apache.tapestry5.services.SelectModelFactory; import org.apache.tapestry5.services.ajax.AjaxResponseRenderer; public class TestAjaxFormLoopWithDateField { public enum TempType { TEXT, DATE } public class Filter { private int id; private Date date; private TempType type; private String value; public Filter() { } public Filter(int id, Date date, TempType type) { this.setId(id); this.setDate(date); this.setType(type); } /** * @return the date */ public Date getDate() { return date; } /** * @param date * the date to set */ public void setDate(Date date) { this.date = date; } /** * @return the id */ public int getId() { return id; } /** * @param id the id to set */ public void setId(int id) { this.id = id; } /** * @return the type */ public TempType getType() { return type; } /** * @param type the type to set */ public void setType(TempType type) { this.type = type; } /** * @return the value */ public String getValue() { return value; } /** * @param value the value to set */ public void setValue(String value) { this.value = value; } } // useful services @Inject private Request request; @Inject private AjaxResponseRenderer ajaxResponseRenderer; /* * Screen fields */ @Property @Persist private List<Filter> filters; @Property private Filter curFilterBean; @InjectComponent private Zone inputFieldZone; @Inject private SelectModelFactory selectModelFactory; @Inject private Block stringValueBlock, dateValueBlock; void setupRender() { filters = new ArrayList<TestAjaxFormLoopWithDateField.Filter>(); if (filters.isEmpty()) filters.add(new Filter(1, null, TempType.TEXT)); } public ValueEncoder<Filter> getFilterEncoder() { return new ValueEncoder<Filter>() { @Override public Filter toValue(String clientValue) { return filters.get(Integer.parseInt(clientValue)); } @Override public String toClient(Filter value) { return String.valueOf(filters.indexOf(value)); } }; } /** * Get unique client side id for zone of input field for * {@link #curFilterBean}. * * @return {@code non-empty} unique client side id */ public String getFieldZoneId() { return "inputField" + getFilterEncoder().toClient(curFilterBean); } /** * Get block for type of {@link #curFilterBean}. * * @return {@code not null} block */ public Block getCase() { Block result = stringValueBlock; if (curFilterBean != null && curFilterBean.getType() != null) { switch (curFilterBean.getType()) { case DATE: result = dateValueBlock; break; } } return result; } /** * Create new {@link Filter} and add it to the list. * * @return {@code not null} {@link Filter} */ Filter onAddRow() { Filter fbean = new Filter(); fbean.setId(this.filters.size()); filters.add(fbean); return fbean; } /** * * @param newType * @param filterBeanId */ void onValueChangedFromTypeSelect(TempType newType, int filterBeanId) { for (Filter curFilterBean : filters) { if (curFilterBean.getId() == filterBeanId) { this.curFilterBean = curFilterBean; break; } } if (request.isXHR()) { ajaxResponseRenderer.addRender(inputFieldZone); } } } <html t:type="mintLayout" title="test AjaxFormLoop" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd" xmlns:p="tapestry:parameter"> <t:form> <t:ajaxformloop t:id="searchRefine" t:source="filters" t:value="curFilterBean" t:encoder="filterEncoder" > <t:if test="curFilterBean"> <div class="row"> <div class="col-xs-5"> <t:select t:id="typeSelect" t:value="curFilterBean.type" t:zone="prop:fieldZoneId" t:context="curFilterBean.id" /> </div> <div class="col-xs-5"> <t:zone t:id="inputFieldZone" id="prop:fieldZoneId"> <t:delegate to="case"/> </t:zone> </div> <div class="col-xs-2"> <t:removerowlink> <p class="form-control-static">remove</p> </t:removerowlink> </div> </div> </t:if> <p:addRow> <t:addrowlink>Add</t:addrowlink> </p:addRow> </t:ajaxformloop> </t:form> <t:block t:id="stringValueBlock"> <input t:type="textField" t:value="curFilterBean.value" /> </t:block> <t:block t:id="dateValueBlock"> <t:DateField t:value="curFilterBean.date" /> </t:block> </html>