You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Tony De Keizer <to...@verticalconnect.net> on 2005/11/01 05:52:26 UTC

RE: Checking if component is in a Form inside the components code

HiJoe,

Thanks for your replies.  They shed some light on the problem.

The post was my first stab at resolving the problem I subsequently  posted
to th emailing list.  I have attached it below for your reference.  I
believe I may not fully understand the render, submit, rewind process and
the relationship between these states and the current state of page
properties and component parameters.  This is something I will need to come
to terms with as I climb that learning curve ...

Maybe the post below may shed some more light on my problem and you may
provide a possible solution ...

Kind Regards
Tony De Keizer
=================================
Dear users,

Sorry this is going to be convoluted post to explain my problem.

I am new to Tapestry and I have been experimenting with existing components
and component development in order to move up the learning curve as fast as
possible.  I am using Tapestry 4. beta 10.

One component I need in my application is a component that is passed a
collection, renders the collection in a table with a checkbox next to each
row, and provides a delete button that when pressed checks the selected rows
and deletes these from the collection.

I have managed to create the base component utilising the foreach component
, checkbox component, and a submit component plus some java code to build
the list of selected row etc.  The component has one required parameter, the
collection.  The remove button has a action listener which gets the selected
list to delete and the current collection and removes the appropriate
entries.

If  I include a single one of these components in a form it works very well.

I then wanted to utilise this component in a form that would include one or
more tabs with each tab incorporating this component with it's own
collection.  The TabPanel is very simple in that it renders the tab names
and then only renders the body of the active tab.  So at any one time only
one tab and it's collection editor content is rendered.
i.e.

<table>
  <tr>
    <span jwcid="@Foreach" source="ognl:tabNames" value="ognl:tabName">
	      <td width="5"></td>
	      <span jwcid="@If" condition="ognl:currentTabActive">
	      	<td class="activetab">
		          <span jwcid="@Insert" value="ognl:tabName"></span>
			</td>
		</span>
	      <span jwcid="@If" condition="ognl:!currentTabActive">
			<td>
				<span jwcid="@DirectLink" listener="ognl:listeners.onTabClicked"
parameters="ognl:descriptor.displayName">
            	   		<span jwcid="@Insert" value="ognl:tabName"></span>
				</span>
			</td>
	      </span>
    </span>
  </tr>
</table>

<div jwcid="@Foreach" source="ognl:tabList" value="ognl:tabName">
	<span jwcid="@If" condition="ognl:currentTabActive">
	<table>
		<tr>
			<td width="100%">
				<span jwcid="collectionEditor" />
			</td>
		</tr>
	</table>
	</span>
</div>

I tested this utilising two tabs and two independent collections.  Now if
the first tab is active and I select the first row for deletion and click
the delete button the first element in the collection bound to the second
tab is removed.  On utilising the Eclipse debugger I found that the
getCollection() call in the listener returned would always return the last
tabs collection not the one that was currently active and the only one being
rendered.

I then modified the remove submit component to bind the listener parameter
not the action parameter to the same listener.  On debugging this I found
the collection that was returned from the getCollection() call was the
correct one for the displayed tab but the selected list updated by the
checkboxes had not been updated due to the submit button not having yet done
a form submit before the listener was invoked.

Can someone please lead me in the right direction to solve this issue or
suggest an alternative, more Tapestry logical, strategy ?
=================================================


> -----Original Message-----
> From: Joe Trewin [mailto:joe@canfactory.com]
> Sent: Tuesday, 1 November 2005 05:28
> To: Tapestry users
> Subject: RE: Checking if component is in a Form inside the components code
>
>
> Sorry - just read the end of the question! Not sure how you could
> trigger a submit, as by the time your component code is run it'll be
> half-way through a rewind. Nothing to stop you getting hold of the
> containing form's listener (if it had one) I guess, and triggering it
> using the invokeListener method, but you'd want to be careful to check
> that that wasn't how your component came to be rewinding in the first
> place.
>
> -----Original Message-----
> From: Joe Trewin [mailto:joe@canfactory.com]
> Sent: 31 October 2005 18:24
> To: Tapestry users
> Subject: RE: Checking if component is in a Form inside the components
> code
>
> Yes it is (assuming Tap 4.0 here, but probably a similar method for
> 3.0). I use something along the lines of:
>
>     IForm form = (IForm)
> cycle.getAttribute(TapestryUtils.FORM_ATTRIBUTE);
>     boolean inForm = (form != null);
>
>     if (inForm) {
>         // ... do something
>     } else {
>         // ... do something else
>     }
>
> If you need mor elaboration, or have trouble, try checking out the
> source code for the For component
> (/framework/src/java/org/apache/tapestry/components/ForBean.java) in the
> Tapestry distribution.
>
> Cheers,
> Joe
>
> -----Original Message-----
> From: Tony De Keizer [mailto:tony@verticalconnect.net]
> Sent: 29 October 2005 03:16
> To: Tapestry users
> Subject: Checking if component is in a Form inside the components code
>
> Is it possible for component java code to check if it is imbedded inside
> a form component and if so trigger a form submit ?
>
> Regards
> ========================================
> Tony De Keizer
>
>
> --
> No virus found in this outgoing message.
> Checked by AVG Free Edition.
> Version: 7.1.362 / Virus Database: 267.12.6/151 - Release Date:
> 28/10/2005
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>
> --
> No virus found in this incoming message.
> Checked by AVG Free Edition.
> Version: 7.1.362 / Virus Database: 267.12.6/151 - Release Date: 28/10/2005
>
--
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.1.362 / Virus Database: 267.12.6/152 - Release Date: 31/10/2005


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


RE: Checking if component is in a Form inside the components code

Posted by Tony De Keizer <to...@verticalconnect.net>.
Hi Richard,

Firstly thanks for the extraordinary effort you have gone to help me with
this issue.

One of the insights is that when doing a form rewind Tapestry seems to
ignore the html components completely(i.e @if's that determine which
elements are being rendered) ,and utilise only the component and page
definitions to find all the necessary state information it thinks it needs.
I thought that only the elements that would be rendered would be utilised
and therefore expected only one collection to be 'active' at any one time.
The displayed one. Silly me  :-)

The current tab component utilises Directlinks for the inactive tabs and
only sets the active tab name which is then rendered.i.e no submit in
between.  I assume this means that any checkbox selection state is lost when
switching tabs.  I am quite happy with this behaviour at the moment i.e
working with one collection at a time, so I suppose this will simplify the
code you provided quite a bit ?
If I need the extended behaviour I suppose I would change the tab
DirectLinks to LinkSubmit's or something similar ?

Again many thanks for the information.  It is much appreciated.

Kind Regards
Tony

> -----Original Message-----
> From: Richard Clark [mailto:rdclark@nextquestion.net]
> Sent: Tuesday, 1 November 2005 17:31
> To: Tapestry users
> Subject: Re: Checking if component is in a Form inside the components code
>
>
> Oops, missed a detail (I was cutting and pasting from existing code
> and editing madly.) Here's new code:
>
> public abstract class CollectionEditPage extends BasePage implements
> PageRenderListener {
>
>    public abstract ListEditMap getMap();
>    public abstract void setMap(ListEditMap map);
>
>    public abstract List getCollections(); // I'm going to assume each
> collection can be iterated like a list
>
>    // Builds the master list
>    public void pageBeginRender(PageEvent event) {
>          super.pageBeginRender(event);
>          ListEditMap map = new ListEditMap();
>          List collections = getCollections();
>          int counter = 0;
>          for (Iterator iter = collections.iterator(); iter.hasNext();) {
>              Collection collection = (Collection) iter.next();
>              for (Iterator itemIter = collection.iterator();
> itemIter.hasNext();) {
>                ItemWrapper wrapper = new ItemWrapper(collection,
> itemIter.next());
>                map.add(new Integer(counter++), wrapper); // key by a
> sequential count
>          }
>          setMap(map);
>      }
>
>      // Use currentItem.item and currentItem.toBeDeleted on your page
>      public abstract void setCurrentItem(ItemWrapper info);
>
>      public void synchronize(IRequestCycle cycle) {
>          ItemWrapper info = (ItemWrapper) getMap().getValue();
>          setCurrentItem(info); // You should handle the case where
> info == null; often by throwing an exception
>      }
>
>      public void doFormSubmission(IRequestCycle cycle) {
>          for (Iterator iter = map.getAllValues().iterator();
> iter.hasNext();) {
>              ItemWrapper wrapper = (ItemWrapper) iter.next();
>              if (wrapper.isToBeDeleted())
>                  wrapper.getCollection().remove(wrapper.getItem());
>          }
>      }
> }
>
> public class ItemWrapper {
>    private Collection collection;
>    private Object item;
>    private boolean toBeDeleted;
>
>    public ItemWrapper(Collection c, Object i) {
>      collection = c;
>      item = i;
>      toBeDeleted = false;
>    }
>
>    public Collection getCollection() { return collection; }
>    public Object getItem() { return item; }
>    public boolean isToBeDeleted() { return toBeDeleted; }
>    public void setToBeDeleted(boolean delete) { toBeDeleted = delete; }
> }
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>
> --
> No virus found in this incoming message.
> Checked by AVG Free Edition.
> Version: 7.1.362 / Virus Database: 267.12.6/152 - Release Date: 31/10/2005
>
--
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.1.362 / Virus Database: 267.12.7/154 - Release Date: 01/11/2005


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


Re: Checking if component is in a Form inside the components code

Posted by Richard Clark <rd...@nextquestion.net>.
Oops, missed a detail (I was cutting and pasting from existing code  
and editing madly.) Here's new code:

public abstract class CollectionEditPage extends BasePage implements  
PageRenderListener {

   public abstract ListEditMap getMap();
   public abstract void setMap(ListEditMap map);

   public abstract List getCollections(); // I'm going to assume each  
collection can be iterated like a list

   // Builds the master list
   public void pageBeginRender(PageEvent event) {
         super.pageBeginRender(event);
         ListEditMap map = new ListEditMap();
         List collections = getCollections();
         int counter = 0;
         for (Iterator iter = collections.iterator(); iter.hasNext();) {
             Collection collection = (Collection) iter.next();
             for (Iterator itemIter = collection.iterator();  
itemIter.hasNext();) {
               ItemWrapper wrapper = new ItemWrapper(collection,  
itemIter.next());
               map.add(new Integer(counter++), wrapper); // key by a  
sequential count
         }
         setMap(map);
     }

     // Use currentItem.item and currentItem.toBeDeleted on your page
     public abstract void setCurrentItem(ItemWrapper info);

     public void synchronize(IRequestCycle cycle) {
         ItemWrapper info = (ItemWrapper) getMap().getValue();
         setCurrentItem(info); // You should handle the case where  
info == null; often by throwing an exception
     }

     public void doFormSubmission(IRequestCycle cycle) {
         for (Iterator iter = map.getAllValues().iterator();  
iter.hasNext();) {
             ItemWrapper wrapper = (ItemWrapper) iter.next();
             if (wrapper.isToBeDeleted())
                 wrapper.getCollection().remove(wrapper.getItem());
         }
     }
}

public class ItemWrapper {
   private Collection collection;
   private Object item;
   private boolean toBeDeleted;

   public ItemWrapper(Collection c, Object i) {
     collection = c;
     item = i;
     toBeDeleted = false;
   }

   public Collection getCollection() { return collection; }
   public Object getItem() { return item; }
   public boolean isToBeDeleted() { return toBeDeleted; }
   public void setToBeDeleted(boolean delete) { toBeDeleted = delete; }
}



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


Re: Checking if component is in a Form inside the components code

Posted by Richard Clark <rd...@nextquestion.net>.
Hi Tony,

   Assume you have a page with 3 tabs (and one collection per tab):  
A, B, and C. Since the user could make a few changes in one tab then  
switch to another and do more, Tapestry has to collect the changes  
from all of the tabs. This collection happens during the rewind.

   For sake of argument, assume each tab has 10 elements. Let's say  
the user deletes the first 2 items in tabs A and B (elements 1, 2,  
11, and 12.) Roughly speaking, as the user clicks delete on each  
element, Tapestry adds another set of parameters to the URL to be sent.

   After submit, tapestry needs to match up the values in the query  
parameters (1, 2, 11, and 12) with the corresponding collection  
elements. That's where rewinding comes in -- Tapestry walks through  
the page as if it were drawing the whole thing again, without  
actually generating HTML, and matches up the query parameters to the  
resulting HTML fields (and the objects that correspond with them.)  
For a tabbed list, Tapestry will draw each tab in turn, which is why  
you're always getting the last tab.

   OK, so how do you fix this? The best way I can think of is at the  
page level:  use a ListEditMap, which you'll populate with _all_ of  
your collections up front (collection A + collection B + collection  
C.) Then, in your form handler, walk through the ListEditMap (which  
will have one "delete" flag per item, for example) and do the actual  
deletions.

Here's a rough example (CAUTION: Not syntax checked)

public abstract class CollectionEditPage extends BasePage implements  
PageRenderListener {

   public abstract ListEditMap getMap();
   public abstract void setMap(ListEditMap map);

   public abstract List getCollections(); // I'm going to assume each  
collection can be iterated like a list

   // Builds the master list
   public void pageBeginRender(PageEvent event) {
         super.pageBeginRender(event);
         ListEditMap map = new ListEditMap();
         List collections = getCollections();
         int counter = 0;
         for (Iterator iter = collections.iterator(); iter.hasNext();) {
             Collection collection = (Collection) iter.next();
             for (Iterator itemIter = collection.iterator();  
itemIter.hasNext();) {
               ItemWrapper wrapper = new ItemWrapper(collection,  
itemIter.next());
               map.add(new Integer(counter++), wrapper); // key by a  
sequential count
         }
         setMap(map);
     }

     public void synchronize(IRequestCycle cycle) {
         ItemWrapper info = (ItemWrapper) getMap().getValue();
         setWorkingModule(info); // You should handle the case where  
info == null; often by throwing an exception
     }

     public void doFormSubmission(IRequestCycle cycle) {
         for (Iterator iter = map.getAllValues().iterator();  
iter.hasNext();) {
             ItemWrapper wrapper = (ItemWrapper) iter.next();
             if (wrapper.isToBeDeleted())
                 wrapper.getCollection().remove(wrapper.getItem());
         }
     }
}

public class ItemWrapper {
   private Collection collection;
   private Object item;
   private boolean toBeDeleted;

   public ItemWrapper(Collection c, Object i) {
     collection = c;
     item = i;
     toBeDeleted = false;
   }

   public Collection getCollection() { return collection; }
   public Object getItem() { return item; }
   public boolean isToBeDeleted() { return toBeDeleted; }
   public void setToBeDeleted(boolean delete) { toBeDeleted = delete; }
}



Hope this helps :)

  ...Richard



  
  

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