You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by "Howard M. Lewis Ship (JIRA)" <ta...@jakarta.apache.org> on 2005/09/09 14:05:30 UTC

[jira] Resolved: (TAPESTRY-631) Foreach doesn't render the nested form components when rewind

     [ http://issues.apache.org/jira/browse/TAPESTRY-631?page=all ]
     
Howard M. Lewis Ship resolved TAPESTRY-631:
-------------------------------------------

    Resolution: Invalid

The Foreach component is working as designed; it does not handle this case.

Because of this, the For component was created.  Use it instead.  It is "form aware" and quite flexible.

> Foreach doesn't render the nested form components when rewind
> -------------------------------------------------------------
>
>          Key: TAPESTRY-631
>          URL: http://issues.apache.org/jira/browse/TAPESTRY-631
>      Project: Tapestry
>         Type: Bug
>   Components: Framework
>     Versions: 4.0
>  Environment: Windows 2000, tomcat, hivemind-1.1-beta3, tapestry-4.0-beta5
>     Reporter: Andrew Love

>
> when rewind, Foreach doesn't render the nested components, the getSource() method always return null, so if there are form compenents in it, and a form components after it, exception will happen.
> the error message is like this:
> Rewind of form admin/productEdit/productForm expected allocated id #5 to be 'Upload', but was 'Submit' (requested by component admin/productEdit/$Submit).
> Here are the code:
> products.html
> <title><span jwcid="@Insert" value="message:userList.title"/></title>
> <content tag="heading"><span key="productList.heading"/></content>
> <!-- Success Messages -->
> <span jwcid="@Conditional" condition="ognl:message != null">
>     <div class="message">
>         <img jwcid="@Any" src="ognl:engine.contextPath+'/images/iconInformation.gif'"
>                 alt="message:icon.information" class="icon" />
>         <span jwcid="@Insert" value="ognl:message" raw="true"/>
>     </div>
> </span>
> <button class="button" onclick="location.href='productEdit.html'"><span key="button.add"/></button>
> <button class="button" onclick="location.href='mainMenu.html'"><span key="button.cancel"/></button>
> <table jwcid="table@contrib:Table" class="list productList" id="productList"
>     rowsClass="ognl:beans.evenOdd.next" row="ognl:row" 
>     columns="product.id:id,productName:name, product.price:price, product.description:description" 
>     source="ognl:listPageOfProducts.list" initialSortColumn="name"
>     arrowUpAsset="ognl:assets.upArrow" arrowDownAsset="ognl:assets.downArrow">
>     <span jwcid="productNameColumnValue@Block">
>         <a jwcid="@DirectLink" listener="listener:edit" parameters="ognl:row.id">
>             <span jwcid="@Insert" value="ognl:row.name"/>
>         </a>
>     </span>
>     <tr jwcid="product_priceColumnValue@Block">
>         <a jwcid="@Any" href="ognl:+'mailto:'+row.price">
>             <span jwcid="@Insert" value="ognl:row.price"/>
>         </a>
>     </tr>
> </table>
> 	<form jwcid="@Form">
> <input class="button" jwcid="@Submit" value="message:button.add" id="add" listener="ognl:listeners.add" 
> 							type="submit" />
> <button class="button" onclick="location.href='mainMenu.html'"><span key="button.cancel"/></button>
> </form>
> <script type="text/javascript">
> highlightTableRows("productList");
> </script>
> products.page
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE page-specification
>       PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
>       "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
> <page-specification class="org.myproduct.webapp.action.ProductList">
>     <inject property="productManager" object="spring:productManager" />    
>     
>     <property name="message"/>
>     <property name="row"/>
>     <property name="listPageOfProducts"/>
>     
>     <bean name="evenOdd" class="org.apache.tapestry.bean.EvenOdd"/>
>     <asset name="upArrow" path="/images/arrow_up.png"/>
>     <asset name="downArrow" path="/images/arrow_down.png"/>
> </page-specification>
> ProductList.java
> package org.myproduct.webapp.action;
> import java.util.HashSet;
> import java.util.Set;
> import net.mlw.vlh.ValueList;
> import net.mlw.vlh.ValueListInfo;
> import org.apache.tapestry.IRequestCycle;
> import org.apache.tapestry.event.PageBeginRenderListener;
> import org.apache.tapestry.event.PageEvent;
> import org.myproduct.model.Image;
> import org.myproduct.model.Product;
> import org.myproduct.service.ProductManager;
> public abstract class ProductList extends BasePage implements PageBeginRenderListener {
>     public abstract ProductManager getProductManager();
>     public abstract ValueList getListPageOfProducts();
>     public abstract void setListPageOfProducts(ValueList products);
>     public void pageBeginRender(PageEvent event) {
>         setListPageOfProducts(getProductManager().listPage("productList",new ValueListInfo()));
>     }
>     public void edit(IRequestCycle cycle) { 
>         ProductForm nextPage = (ProductForm) cycle.getPage("admin/productEdit");
>         Product product=findProduct(cycle);
>         initialProduct(product);
>         fetchProduct(cycle,product,nextPage);
>     }
>     
>     public void add(IRequestCycle cycle) {
>         ProductForm nextPage = (ProductForm) cycle.getPage("admin/productEdit");
>         Product product=new Product();
>         initialProduct(product);
>         fetchProduct(cycle,product,nextPage);
>     }
>     
>     public void detail(IRequestCycle cycle) { 
>         ProductForm nextPage = (ProductForm) cycle.getPage("productDetail");
>         Product product=findProduct(cycle);
>         fetchProduct(cycle,product,nextPage);
>     }
>     
>     private void fetchProduct(IRequestCycle cycle,Product product,ProductForm nextPage){
>         nextPage.setProduct(product);
>         cycle.activate(nextPage);
>     }
>     
>     private Product findProduct(IRequestCycle cycle){
>         Object[] parameters = cycle.getListenerParameters();
>         Long id = (Long) parameters[0];
>         Product product = getProductManager().getProduct(id);
>         if (log.isDebugEnabled()) {
>             log.debug("fetching product with id: " + id);
>         }
>         return product;
>     }
>     
>     private void initialProduct(Product product){
>         Set images=product.getImages();
>         if(images==null){
>             images=new HashSet();
>             product.setImages(images);
>         }
>         images.add(new Image());        
>     }
> }
> productEdit.html
> <html>
> <head>
>   <title><span jwcid="@Insert" value="message:product.detail"/></title>
>   <content tag="heading"></content>
> </head>
> <body jwcid="@Body">
> 	<!-- Error Messages -->
> 	<span jwcid="@Conditional" condition="ognl:beans.delegate.hasErrors">
> 		<div class="error">
> 			<img jwcid="@Any" 
> 				src="ognl:engine.contextPath+'/images/iconWarning.gif'" 
> 				alt="message:icon.warning" class="icon" />
> 			<span jwcid="@Delegator" delegate="ognl:beans.delegate.firstError" 
> 				raw="true"> Error Message </span>
> 		</div>
> 	</span>
> 	<!-- Success Messages -->
> 	<span jwcid="@Conditional" condition="ognl:message != null">
> 		<div class="message">
> 			<img jwcid="@Any" 
> 				src="ognl:engine.contextPath+'/images/iconInformation.gif'" 
> 				alt="message:icon.information" class="icon" />
> 			<span jwcid="@Insert" value="ognl:message" raw="true"></span>
> 		</div>
> 	</span>
> 	<div class="separator"></div>
> 	<form jwcid="productForm@Form" delegate="ognl:beans.delegate" 
> 		id="productForm">
> 		<input jwcid="@Hidden" value="ognl:product.id" type="hidden" />
> 		<table class="detail" cellpadding="10" cellspacing="10">
> 			<tbody>
> 				<tr>
> 				 <td width="45%">
> 				  <table width="100%">
> 				   <tr>
> 					<th><span jwcid="@Insert" value="message:productName"/></th>
> 					<td>
> 						<div>
> 							<input jwcid="@TextField" value="ognl:product.name" 
> 								type="text" />
> 						</div>
> 					</td>
> 				   </tr>
> 				<tr>
> 					<th><span jwcid="@Insert" value="message:product.price"/></th>
> 					<td>
> 						<input jwcid="priceField" size="40" type="text" />
> 					</td>
> 				</tr>
> 				<tr>
> 					<th><span jwcid="@Insert" value="message:product.description"/></th>
> 					<td>
> 						<input jwcid="@TextField" size="40" 
> 							value="ognl:product.description" type="text" />
> 					</td>
> 				</tr>
> 				</table>
> 				</td>
> 					
> 					
> 				<td>
> 					<table>
> 					<tr jwcid="images">
> 					<td>
> 					<img jwcid="productImg" />
> 					<br />
> 					<input jwcid="@Upload" file="ognl:image.uploadFile" size="50" 
> 							type="file" />
> 					</td>
> 					</tr>
> 					</table>
> 						
> 					</td>
> 				</tr>
> 				<tr>
> 					<td colspan="2">
> 					
> 						<input class="button" jwcid="@Submit" 
> 							value="message:button.save" id="save" 
> 							listener="ognl:listeners.save" type="submit" />
> 						<span jwcid="@contrib:FormConditional" 
> 							condition="ognl:product.name != null">
> 							<input class="button" jwcid="@Submit" 
> 								value="message:button.delete" id="delete" 
> 								listener="ognl:listeners.delete" 
> 								onclick="form.onsubmit = null" type="submit" />
> 							<!-- Removed confirm since WebTest can't handle it: ;return confirmDelete('User') -->
> 						</span>
> 						<input class="button" jwcid="@Submit" 
> 							value="message:button.cancel" id="cancel" 
> 							listener="ognl:listeners.cancel" 
> 							onclick="form.onsubmit = null" type="submit" />
> 					</td>					
> 				</tr>
> 			</tbody>
> 		</table>
> 	</form>
> 	<script type="text/javascript"> <span jwcid="@Conditional" 
> 		condition="ognl:product.name == null"> 
> 		document.getElementById("name").focus(); </span> <span 
> 		jwcid="@Conditional" condition="ognl:product.price == null"> 
> 		document.getElementById("price").focus(); </span> 
> 		highlightFormElements(); </script>
> </body>
> </html>
> productEdit.page
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE page-specification 
>     PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN" 
>     "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd"> 
>         
> <page-specification class="org.myproduct.webapp.action.ProductForm">
>     <inject property="productManager" object="spring:productManager" />
>         
>     <property name="product"/>
>     <bean name="delegate" class="org.myproduct.webapp.action.Validator"/>
> 	<bean name="priceValidator" class="org.apache.tapestry.valid.NumberValidator">
> 	    <set name="required" value="true"/>
> 	    <set name="valueType" value="'float'"/>    
> 	</bean>
> 	  <component id="images" type="Foreach">
> 	    <binding name="source" value="product.images"/>
> 	    <binding name="value" value="image"/>
> 	    <binding name="element" value="literal:tr"/>
> 	  </component>
>     <component id="priceField" type="ValidField">
>         <binding name="value" value="product.price"/>
>         <binding name="validator" value="bean:priceValidator"/>
>         <binding name="displayName" value="product.price"/>
>     </component>
>     <component id="productImg" type="Any">
>         <binding name="src" value="asset:productImage"/>
>     </component>
> 	<asset name="productImage" path="ognl:image.url+image.name"/>
> </page-specification>
> package org.myproduct.webapp.action;
> import java.io.File;
> import java.io.FileOutputStream;
> import java.io.IOException;
> import java.io.InputStream;
> import java.io.OutputStream;
> import java.nio.ByteBuffer;
> import java.util.ArrayList;
> import java.util.List;
> import java.util.Set;
> import org.apache.tapestry.IRequestCycle;
> import org.apache.tapestry.event.PageBeginRenderListener;
> import org.apache.tapestry.event.PageEvent;
> import org.apache.tapestry.request.IUploadFile;
> import org.myproduct.Constants;
> import org.myproduct.model.Image;
> import org.myproduct.model.Product;
> import org.myproduct.service.ProductManager;
> public abstract class ProductForm extends BasePage implements PageBeginRenderListener {
>     public abstract ProductManager getProductManager();
>     public abstract void setProduct(Product product);
>     public abstract Product getProduct();
>     public abstract Image getImage();
>     
>     public void pageBeginRender(PageEvent event) {
>         if ((getProduct() == null) && !event.getRequestCycle().isRewinding()) {
>             setProduct(new Product());
>         } else if (event.getRequestCycle().isRewinding()) { // add
>             setProduct(new Product());
>         }
>     }
>     public void cancel(IRequestCycle cycle) {
>         if (log.isDebugEnabled()) {
>             log.debug("Entering 'cancel' method");
>         }
>         cycle.activate("admin/products");
>     }
>     public void delete(IRequestCycle cycle) {
>         if (log.isDebugEnabled()) {
>             log.debug("entered 'delete' method");
>         }
>         getProductManager().removeProduct(getProduct().getId());
>         ProductList nextPage = (ProductList) cycle.getPage(Constants.AdminProductListPage);
>         nextPage.setMessage(getMessage("product.deleted"));
>         cycle.activate(nextPage);
>     }
>     public void save(IRequestCycle cycle) throws IOException {
>         if (getValidationDelegate().getHasErrors()) {
>             return;
>         }
>         boolean isNew = (getProduct().getId() == null);
>         Product product=getProduct();
>         String key = (isNew) ? "product.added" : "product.updated";
>         upload(cycle,product);
>         
>         this.getProductManager().saveProduct(product);
>         if (isNew) {
>             ProductList nextPage = (ProductList) cycle.getPage(Constants.AdminProductListPage);
>             nextPage.setMessage(getMessage(key));
>             cycle.activate(nextPage);
>         } else {
>             ProductForm nextPage = (ProductForm) cycle.getPage(Constants.AdminProductPage);
>             nextPage.setMessage(getMessage(key));
>             cycle.activate(nextPage); // return to current page
>         }
>     }
>     
>     private void upload(IRequestCycle cycle,Product product) throws IOException {
>     	
>     	Set images=product.getImages();
>     	List imagesList=new ArrayList(images);
>         // write the file to the filesystem
>         // the directory to upload to
>         String uploadDir =
>             getServletContext().getRealPath("/img") + "/";
>         // Create the directory if it doesn't exist
>         File dirPath = new File(uploadDir);
>         if (!dirPath.exists()) {
>             dirPath.mkdirs();
>         }
>     	for(int i=0;i<imagesList.size();i++){
>     		Image image=(Image) imagesList.get(i);    		
>             IUploadFile file = image.getUploadFile();            
>             if (file == null) {
>             	if(image.getId()==null){
>             		imagesList.remove(image);
>             		i--;
>             	}
>                 continue;
>             }
>             //retrieve the file data
>             InputStream stream = file.getStream();
>             int fileSize=(int)file.getSize();
>             ByteBuffer bbuffer=ByteBuffer.allocate(fileSize);
>             byte[] buffer = new byte[8192];
>             int bytesRead = 0;
>             while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
>             	bbuffer.put(buffer,0,bytesRead);
>             }
>             stream.close();
>             
>             //first, store the file to database
>             image.setName(file.getFileName());
>             image.setFile(bbuffer.array());
>             image.setUrl(uploadDir);
>             image.setProduct(product);
>             
>             //write the file to the file specified
>             OutputStream bos =
>                 new FileOutputStream(uploadDir + file.getFileName());
>                 bos.write(bbuffer.array(), 0, fileSize);
>             bos.close();
>             //close the stream
>     	}   	
>     }
> }

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org