tapestry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Howard M. Lewis Ship (JIRA)" <j...@apache.org>
Subject [jira] [Updated] (TAP5-280) Fields injected by AjaxFormLoop sometimes have incorrect values after submits where validation fails.
Date Thu, 25 Jul 2013 00:29:49 GMT

     [ https://issues.apache.org/jira/browse/TAP5-280?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Howard M. Lewis Ship updated TAP5-280:
--------------------------------------

    Labels: ajax-form-loop  (was: )
    
> 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
>              Labels: ajax-form-loop
>         Attachments: MyAjaxFormLoop.java
>
>
> 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.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Mime
View raw message