[
https://issues.apache.org/jira/browse/TAP5-280?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12919175#action_12919175
]
Alexander Gavrilov commented on TAP5-280:
-----------------------------------------
Can we increase priority of this issue, besause without fixing it we can't have
"true" dynamic forms in tapestry
> Fields injected by AjaxFormLoop sometimes have incorrect values after submits
> where validation fails.
> -----------------------------------------------------------------------------------------------------
>
> Key: TAP5-280
> URL: https://issues.apache.org/jira/browse/TAP5-280
> Project: Tapestry 5
> Issue Type: Bug
> Components: tapestry-core
> Affects Versions: 5.0.15
> Reporter: Shawn Brownfield
>
> Using the below .tml, .java. and .js files:
> 1. Click Add Group.
> 2. Add values "a" and "1" in the upper group, "c" and "3" in the lower group.
> 3. Click Save.
> 4. Add a row in the upper group and enter "b" and "b".
> 5. Click Save.
> ==> Values "c" and "3" are copied into the last row of the upper group
> (validation has failed).
> The only values ever lost/copied over are values of rows that were inserted
> via the addRowLink. Upon failure of validation, it looks as though the
> ValidationTracker is trying to look up the values for the new rows using the
> control id from the render phase, but the submission had
> "mangled"/"uniquified" control ids (with :?????? added) for all the inputs,
> so that is how these values are stored in the ValidationTracker.
> AjaxFormLoopTest.tml:
> <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
> <head/>
> <body>
> <h1>Nested AjaxFormLoop Test</h1>
> <t:form t:id="formLoopTestForm" t:clientValidation="false">
>
> <div t:type="AjaxFormLoop"
> t:id="outerFormLoop"
> t:source="outerList"
> t:value="tempOuter"
> t:encoder="outerEncoder"
> >
> <table style="background-color: #ece9d8;
> margin: 2px 0;">
> <tbody>
> <tr>
> <th>String</th>
> <th>Number</th>
> </tr>
> <tr t:type="AjaxFormLoop"
> t:id="innerFormLoop"
>
> t:source="tempOuter.list"
> t:value="tempInner"
> t:context="tempOuter.id"
> t:encoder="innerEncoder"
> >
> <td><t:textField
> t:value="tempInner.string"/></td>
> <td><t:textField
> t:value="tempInner.number"/></td>
> <t:parameter
> name="addRow">
> <td colspan="2">
>
> <t:addRowLink>Add Row</t:addRowLink>
> </td>
> </t:parameter>
> </tr>
> </tbody>
> </table>
> <t:parameter name="addRow">
> <t:addRowLink>Add Group</t:addRowLink>
> </t:parameter>
> </div>
>
> <br/>
>
> <t:submit t:id="save" value="Save"/>
> <t:actionLink t:id="clear">Clear</t:actionLink>
> </t:form>
> </body>
> </html>
> AjaxFormLoopTest.java:
> @IncludeJavaScriptLibrary("context:javascript/script.js")
> public class AjaxFormLoopTest {
> @Persist
> @Property
> private List<Outer> outerList;
>
> @Property
> private Outer tempOuter;
>
> @Property
> private Inner tempInner;
>
> void beginRender() {
> if (outerList == null) {
> outerList = new ArrayList<Outer>();
> Outer outer = new Outer(0);
> outerList.add(outer);
> }
> }
> Object onAddRowFromOuterFormLoop() {
> int nextId = outerList.size() + 1;
> Outer outer = new Outer(nextId);
> outerList.add(outer);
>
> return outer;
> }
>
> Object onAddRowFromInnerFormLoop(Integer outerId) {
> Outer outer = getOuterById(outerId);
> List<Inner> list = outer.getList();
> Inner inner = new Inner();
> list.add(inner);
> inner.setOuter(outer);
>
> return inner;
> }
>
> void onActionFromClear() {
> outerList = null;
> }
> ////////////////////////////////
> // Encoders
> ////////////////////////////////
> private final PrimaryKeyEncoder<Integer, Outer> outerEncoder =
> new PrimaryKeyEncoder<Integer, Outer>() {
> public void prepareForKeys(List arg0) {}
> public Integer toKey(Outer outer) {
> return outer.getId();
> }
> public Outer toValue(Integer key) {
> Outer ret = getOuterById(key);
> if (ret == null) throw new
> RuntimeException("outerEncoder could not retreive item for key:" + key);
> return ret;
> }
> };
> public PrimaryKeyEncoder<Integer, Outer> getOuterEncoder() { return
> outerEncoder; }
> private final PrimaryKeyEncoder<EncoderKey, Inner> innerEncoder =
> new PrimaryKeyEncoder<EncoderKey, Inner>() {
> public void prepareForKeys(List arg0) {}
> public EncoderKey toKey(Inner inner) {
> Outer outer = inner.getOuter();
> return new EncoderKey(outer.getId(),
> outer.getList().indexOf(inner));
> }
> public Inner toValue(EncoderKey key) {
> Inner ret = null;
>
> Outer outer = getOuterById(key.getGroupId());
> if (outer != null) {
> ret =
> outer.getList().get(key.getIndex());
> }
>
> if (ret == null) throw new
> RuntimeException("innerEncoder could not retreive item for key:" + key);
> return ret;
> }
> };
> public PrimaryKeyEncoder<EncoderKey, Inner> getInnerEncoder() { return
> innerEncoder; }
> ////////////////////////////////
> // Helpers
> ////////////////////////////////
> private Outer getOuterById(Integer outerId) {
> Outer outer = null;
> for (Outer o : outerList) {
> if (o.getId().equals(outerId)) {
> outer = o;
> break;
> }
> }
>
> return outer;
> }
>
> // Referenced classes
> public static class Outer {
> private Integer id;
> private List<Inner> list;
>
> public Outer(Integer id) {
> this.id = id;
> list = new ArrayList<Inner>();
> Inner inner = new Inner();
> inner.setOuter(this);
> list.add(inner);
> }
> public Integer getId() { return id; }
> public void setId(Integer id) { this.id = id; }
> public List<Inner> getList() { return list; }
> public void setList(List<Inner> list) { this.list = list; }
> }
>
> public static class Inner {
> private String string;
> private Integer number;
> private Outer outer;
> public String getString() { return string; }
> public void setString(String string) { this.string = string; }
> public Integer getNumber() { return number; }
> public void setNumber(Integer number) { this.number = number; }
>
> public Outer getOuter() { return outer; }
> public void setOuter(Outer outer) { this.outer = outer; }
> }
> public static class EncoderKey implements Serializable{
> private static final long serialVersionUID = 1L;
>
> private final Integer groupId;
> private final Integer index;
>
> public final static String SEPARATOR = "_";
>
>
> public EncoderKey(Integer q, Integer i){
> this.groupId = q;
> this.index = i;
> }
>
> public Integer getGroupId() {
> return groupId;
> }
> public Integer getIndex() {
> return index;
> }
>
> @Override
> public boolean equals(Object obj){
> if (!(obj instanceof EncoderKey)){
> return super.equals(obj);
> }
> EncoderKey other = (EncoderKey)obj;
> return this.groupId.equals(other.groupId) &&
> this.index.equals(other.index);
> }
>
> @Override
> public int hashCode(){
> return this.groupId * this.index * 31;
> }
>
> public int compareTo(EncoderKey other){
> int test = this.groupId.compareTo(other.groupId);
> return test != 0 ? test :
> this.index.compareTo(other.index);
> }
> public String toString(){
> return "Group: " + groupId + " Index: " + index;
> }
>
> public String encode(){
> return
> this.getGroupId()+EncoderKey.SEPARATOR+this.getIndex();
> }
> }
> }
> script.js:
> /** Override to prevent client-side validation. */
> Tapestry.Initializer.validate = function (field, specs) { return; };
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.