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