[ 
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.

Reply via email to