You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Inge Solvoll <in...@gmail.com> on 2006/02/14 13:04:34 UTC

page state/cycle problem

I would like to provoke some debate on whether this is a good design pattern
or not:

public void pageBeginRender(PageEvent event) {
  initState();
  readItemsFromDatabase();
}

private Collection readItemsFromDatabase() {
  return getDatabaseConnection().getItems();
}

private void initState() {
  // Init all crucial page state here
}

My problem is that some ids in hidden inputs are needed by the initState
method. These values are not available in the pageBeginRender method during
rewind, because the Hidden components containing them haven't been rendered
yet. I need this state information on a per-request basis, not per-session,
so it is not possible to persist the page property. So far, I'm solving this
by using good-old request parameters, and reading them the old servlet way
in the pageBeginRender method like this:

String crucialId = getRequest().getParameter("crucialId");
page.setCrucialId(new Long(crucialId));

I generally run into a lot of problems trying to find a good pattern for
setting up data to fit with the RequestCycle. I have ended up doing the
database reading in the pageBeginRender method, meaning that my data for the
page is being read on every single rewind and render. I find it a bit hard
to understand how to achieve this:

On render:
- Read data from database and set page properties

On rewind:
- Create non-null, empty, page properties ready to be populated from the
request.

My rewind step here often fails, and I don't see why. My page properties
don't seem to be populated, when I leave them as, say, a non-null empty
java.util.Collection to be populated with items from the request.

Long and not very concentrated post, I actually don't know where to start
here :)

Inge

Re: page state/cycle problem

Posted by Onno Scheffers <on...@piraya.nl>.
Inge Solvoll schreef:

>I would like to provoke some debate on whether this is a good design pattern
>or not:
>
>public void pageBeginRender(PageEvent event) {
>  initState();
>  readItemsFromDatabase();
>}
>
>private Collection readItemsFromDatabase() {
>  return getDatabaseConnection().getItems();
>}
>
>private void initState() {
>  // Init all crucial page state here
>}
>  
>
Hi Inge,

I do that as well sometimes. Not sure if it is a good design pattern 
though ;oP
There are times when you need some of the hidden parameters-values for 
handling the pageBeginRender or PageValidate on the rewind-phase,  while 
the Hidden components haven't populated their properties yet. I don't 
know of any other way of doing it but reading the values directly from 
the request.

>I generally run into a lot of problems trying to find a good pattern for
>setting up data to fit with the RequestCycle. I have ended up doing the
>database reading in the pageBeginRender method, meaning that my data for the
>page is being read on every single rewind and render. I find it a bit hard
>to understand how to achieve this:
>  
>
If I have to fetch items from the database and I don't want to let 
Tapestry persist them and I need them on both the rewind-phase as well 
as the render-phase, then I usually make the properties for those items 
concrete instead of abstract.
I also usually give those properties a lazy getter (if property is null, 
fetch from database).
By making those properties concrete I have control over when they get 
cleared. I only clear the properties after the render-phase (not after 
the rewind-phase). Since the same page-instance gets used for rendering 
after a rewind has taken place (same request is being handled), I only 
need to fetch the data from the database once.

If anyone has any better solution to this, I would love to hear about it.

Regards,

Onno

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


Re: page state/cycle problem

Posted by Inge Solvoll <in...@gmail.com>.
Lots of good stuff here!

I guess my next project will have to be building a proof of concept for a
way of handling the cycle issues. I like the thought of entirely skipping
initialization on rewind, but so far this has given me a lot of headache
because of nullpointers, empty collections not populated the way I excepted,
and so forth...

This will be a lot easier to see if I remove all the clutter of a real-world
example, and create a simple test page containing what I need to test this,
if I find out something interesting, I will post the entire code in this
thread.

Thanks

Inge

On 2/15/06, Shawn Church <sh...@boxity.com> wrote:
>
> I've been there; it's always the little foxes...  I am honestly not sure
> whether I've ever tried exactly this scenario, but I might try and
> reproduce it myself.  I almost always need (or think I will sometime
> need) multiple values to live together, so I usually create a bean
> contained in a Collection of some sort.  In that case, the @For value is
> the bean, and the @TextField input value is a bean property, so there is
> no conflict when it comes to getting/setting.
>
> If I have a chance tomorrow, I'll try and test this myself.  It looks
> like OGNL should have handled your initial attempt, but you still would
> have needed the hidden vals.  There was an OGNL bug "Fixed bug with not
> calling conversion on setting value in array" fixed in 2.6.6, so you
> might see which version you are using.  I may be out in left field here
> though.
>
> Shawn
>
> Todd O'Bryan wrote:
> > I just didn't realize that (a) if I used something as a source in a
> > @For I also needed to put it in a hidden field or make it persistent,
> > (b) using the value="..." idiom in a @For doesn't update the source,
> > at least with arrays.
> >
> > I think I would have figured out either of those pretty quickly. With
> > both together, I ate literally hours over the last week or so.
> >
> > Todd
> >
> > On Feb 14, 2006, at 10:28 PM, Shawn Church wrote:
> >
> >> Todd,
> >>
> >> For me, either carefully-controlled session-persisted properties or
> >> hidden form values have worked best.  ListEdit might have helped you
> >> in this case, but I've always found it to be pretty cumbersome, and
> >> in the end all it really does is take care of setting up the hidden
> >> fields for you.
> >>
> >> Shawn
> >>
> >> Todd O'Bryan wrote:
> >>>
> >>> On Feb 14, 2006, at 8:19 PM, Shawn Church wrote:
> >>>>
> >>>> Typically, pageBeginRender is invoked to initialize the page from
> >>>> properties which (by this time) have already been set either by a
> >>>> calling page, by a previous render, or by external page
> >>>> initialization (by implementing IExternalPage).  After page
> >>>> rendering is complete, the rendered response is sent to the
> >>>> client.  The rewind phase is only invoked if a form is submitted.
> >>>> In this case, the form's listener method is invoked (where you can
> >>>> do whatever you like with the submitted form values), after which
> >>>> pageBeginRender will again be invoked to render the page.
> >>>>
> >>>> Tapestry makes all of what you are trying to do very simple, but it
> >>>> is important to understand exactly how it works.  Tapestry in
> >>>> Action covers all of this for Tapestry 3, and Kent Tong's book is a
> >>>> tremendous resource for Tapestry 4.
> >>>
> >>> There is a gotcha that I just spent the last week or so being very
> >>> annoyed by (I'm still in Tapestry 3.0.3).
> >>>
> >>> I had a String[] of values. I was populating the array in
> >>> pageBeginRender() and then passing the values so gotten to the next
> >>> page in the form's listener.
> >>>
> >>> I tried
> >>>
> >>> <span jwcid="@base:For" source="ognl:vals" value="ognl:val">
> >>> <input type="text" jwcid="@TextField" value="ognl:val" />
> >>> </span>
> >>>
> >>> Unfortunately, vals[0]-vals[n] were not getting updated...they were
> >>> exactly what they used to be. So I tried updating the array directly
> >>>
> >>> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
> >>> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
> >>> </span>
> >>>
> >>> This seemed to update the array correctly, but my handle to the
> >>> array became null and any calls to getVals()[0] in the listener
> >>> returned an NullPointerException. Now, vals was not a persistent
> >>> property, so it was getting lost. I could either make it persistent
> >>> (back button nightmares) or the following, which finally worked:
> >>>
> >>> <input type="hidden" jwcid="@Hidden" value="ognl:vals">
> >>> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
> >>> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
> >>> </span>
> >>>
> >>> Now I could access the array using getVals() in the listener method
> >>> and it contained the updated values.
> >>>
> >>> Did I do something wrong or is this just way more convoluted than it
> >>> should be? Or would ListEdit have saved me some trouble?
> >>>
> >>> Todd
> >>>
> >>> ---------------------------------------------------------------------
> >>> 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
> >>
> >
> >
> > ---------------------------------------------------------------------
> > 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
>
>

Re: page state/cycle problem

Posted by Shawn Church <sh...@boxity.com>.
I ran a few tests and was able to easily reproduce your original
problem.  I first tested as you did with an Array of Strings, and then
with an ArrayList of Strings, and finally with an ArrayList of Integers.
 In none of these cases was I able to see my inputs reflected in the
submitted (hidden) list of values in my form listener.  I was also using
ognl 2.6.7, so there is no issue there.  

I think the main issue is the fact that Strings are immutable.  Putting
a String into a Java bean having normal accessors and mutators (getters
and setters), everything works fine with one caveat.  If you are using
@base:For and you have a hidden field to store your list, you will need
to specify formless="ognl:true" to prevent the original values from
being retained.  If you are using @Foreach, it will work without any issues.

Sorry for the short response, but I have a meeting in a couple of
minutes.  Hopefully this clears things up a little.

Shawn

Quoting Shawn Church <sh...@boxity.com>:

> I've been there; it's always the little foxes...  I am honestly not
> sure 
> whether I've ever tried exactly this scenario, but I might try and 
> reproduce it myself.  I almost always need (or think I will sometime
> 
> need) multiple values to live together, so I usually create a bean 
> contained in a Collection of some sort.  In that case, the @For value
> is 
> the bean, and the @TextField input value is a bean property, so there
> is 
> no conflict when it comes to getting/setting.
> 
> If I have a chance tomorrow, I'll try and test this myself.  It looks
> 
> like OGNL should have handled your initial attempt, but you still
> would 
> have needed the hidden vals.  There was an OGNL bug "Fixed bug with
> not 
> calling conversion on setting value in array" fixed in 2.6.6, so you
> 
> might see which version you are using.  I may be out in left field
> here 
> though.
> 
> Shawn
> 
> Todd O'Bryan wrote:
> > I just didn't realize that (a) if I used something as a source in a
> 
> > @For I also needed to put it in a hidden field or make it
> persistent, 
> > (b) using the value="..." idiom in a @For doesn't update the
> source, 
> > at least with arrays.
> >
> > I think I would have figured out either of those pretty quickly.
> With 
> > both together, I ate literally hours over the last week or so.
> >
> > Todd
> >
> > On Feb 14, 2006, at 10:28 PM, Shawn Church wrote:
> >
> >> Todd,
> >>
> >> For me, either carefully-controlled session-persisted properties
> or 
> >> hidden form values have worked best.  ListEdit might have helped
> you 
> >> in this case, but I've always found it to be pretty cumbersome,
> and 
> >> in the end all it really does is take care of setting up the
> hidden 
> >> fields for you.
> >>
> >> Shawn
> >>
> >> Todd O'Bryan wrote:
> >>>
> >>> On Feb 14, 2006, at 8:19 PM, Shawn Church wrote:
> >>>>
> >>>> Typically, pageBeginRender is invoked to initialize the page
> from 
> >>>> properties which (by this time) have already been set either by
> a 
> >>>> calling page, by a previous render, or by external page 
> >>>> initialization (by implementing IExternalPage).  After page 
> >>>> rendering is complete, the rendered response is sent to the 
> >>>> client.  The rewind phase is only invoked if a form is
> submitted.  
> >>>> In this case, the form's listener method is invoked (where you
> can 
> >>>> do whatever you like with the submitted form values), after
> which 
> >>>> pageBeginRender will again be invoked to render the page.
> >>>>
> >>>> Tapestry makes all of what you are trying to do very simple, but
> it 
> >>>> is important to understand exactly how it works.  Tapestry in 
> >>>> Action covers all of this for Tapestry 3, and Kent Tong's book
> is a 
> >>>> tremendous resource for Tapestry 4.
> >>>
> >>> There is a gotcha that I just spent the last week or so being
> very 
> >>> annoyed by (I'm still in Tapestry 3.0.3).
> >>>
> >>> I had a String[] of values. I was populating the array in 
> >>> pageBeginRender() and then passing the values so gotten to the
> next 
> >>> page in the form's listener.
> >>>
> >>> I tried
> >>>
> >>> <span jwcid="@base:For" source="ognl:vals" value="ognl:val">
> >>> <input type="text" jwcid="@TextField" value="ognl:val" />
> >>> </span>
> >>>
> >>> Unfortunately, vals[0]-vals[n] were not getting updated...they
> were 
> >>> exactly what they used to be. So I tried updating the array
> directly
> >>>
> >>> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
> >>> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
> >>> </span>
> >>>
> >>> This seemed to update the array correctly, but my handle to the 
> >>> array became null and any calls to getVals()[0] in the listener 
> >>> returned an NullPointerException. Now, vals was not a persistent
> 
> >>> property, so it was getting lost. I could either make it
> persistent 
> >>> (back button nightmares) or the following, which finally worked:
> >>>
> >>> <input type="hidden" jwcid="@Hidden" value="ognl:vals">
> >>> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
> >>> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
> >>> </span>
> >>>
> >>> Now I could access the array using getVals() in the listener
> method 
> >>> and it contained the updated values.
> >>>
> >>> Did I do something wrong or is this just way more convoluted than
> it 
> >>> should be? Or would ListEdit have saved me some trouble?
> >>>
> >>> Todd
> >>>
> >>>
> ---------------------------------------------------------------------
> >>> 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
> >>
> >
> >
> >
> ---------------------------------------------------------------------
> > 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
> 




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


Re: page state/cycle problem

Posted by Shawn Church <sh...@boxity.com>.
I've been there; it's always the little foxes...  I am honestly not sure 
whether I've ever tried exactly this scenario, but I might try and 
reproduce it myself.  I almost always need (or think I will sometime 
need) multiple values to live together, so I usually create a bean 
contained in a Collection of some sort.  In that case, the @For value is 
the bean, and the @TextField input value is a bean property, so there is 
no conflict when it comes to getting/setting.

If I have a chance tomorrow, I'll try and test this myself.  It looks 
like OGNL should have handled your initial attempt, but you still would 
have needed the hidden vals.  There was an OGNL bug "Fixed bug with not 
calling conversion on setting value in array" fixed in 2.6.6, so you 
might see which version you are using.  I may be out in left field here 
though.

Shawn

Todd O'Bryan wrote:
> I just didn't realize that (a) if I used something as a source in a 
> @For I also needed to put it in a hidden field or make it persistent, 
> (b) using the value="..." idiom in a @For doesn't update the source, 
> at least with arrays.
>
> I think I would have figured out either of those pretty quickly. With 
> both together, I ate literally hours over the last week or so.
>
> Todd
>
> On Feb 14, 2006, at 10:28 PM, Shawn Church wrote:
>
>> Todd,
>>
>> For me, either carefully-controlled session-persisted properties or 
>> hidden form values have worked best.  ListEdit might have helped you 
>> in this case, but I've always found it to be pretty cumbersome, and 
>> in the end all it really does is take care of setting up the hidden 
>> fields for you.
>>
>> Shawn
>>
>> Todd O'Bryan wrote:
>>>
>>> On Feb 14, 2006, at 8:19 PM, Shawn Church wrote:
>>>>
>>>> Typically, pageBeginRender is invoked to initialize the page from 
>>>> properties which (by this time) have already been set either by a 
>>>> calling page, by a previous render, or by external page 
>>>> initialization (by implementing IExternalPage).  After page 
>>>> rendering is complete, the rendered response is sent to the 
>>>> client.  The rewind phase is only invoked if a form is submitted.  
>>>> In this case, the form's listener method is invoked (where you can 
>>>> do whatever you like with the submitted form values), after which 
>>>> pageBeginRender will again be invoked to render the page.
>>>>
>>>> Tapestry makes all of what you are trying to do very simple, but it 
>>>> is important to understand exactly how it works.  Tapestry in 
>>>> Action covers all of this for Tapestry 3, and Kent Tong's book is a 
>>>> tremendous resource for Tapestry 4.
>>>
>>> There is a gotcha that I just spent the last week or so being very 
>>> annoyed by (I'm still in Tapestry 3.0.3).
>>>
>>> I had a String[] of values. I was populating the array in 
>>> pageBeginRender() and then passing the values so gotten to the next 
>>> page in the form's listener.
>>>
>>> I tried
>>>
>>> <span jwcid="@base:For" source="ognl:vals" value="ognl:val">
>>> <input type="text" jwcid="@TextField" value="ognl:val" />
>>> </span>
>>>
>>> Unfortunately, vals[0]-vals[n] were not getting updated...they were 
>>> exactly what they used to be. So I tried updating the array directly
>>>
>>> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
>>> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
>>> </span>
>>>
>>> This seemed to update the array correctly, but my handle to the 
>>> array became null and any calls to getVals()[0] in the listener 
>>> returned an NullPointerException. Now, vals was not a persistent 
>>> property, so it was getting lost. I could either make it persistent 
>>> (back button nightmares) or the following, which finally worked:
>>>
>>> <input type="hidden" jwcid="@Hidden" value="ognl:vals">
>>> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
>>> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
>>> </span>
>>>
>>> Now I could access the array using getVals() in the listener method 
>>> and it contained the updated values.
>>>
>>> Did I do something wrong or is this just way more convoluted than it 
>>> should be? Or would ListEdit have saved me some trouble?
>>>
>>> Todd
>>>
>>> ---------------------------------------------------------------------
>>> 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
>>
>
>
> ---------------------------------------------------------------------
> 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


Re: page state/cycle problem

Posted by Todd O'Bryan <to...@mac.com>.
I just didn't realize that (a) if I used something as a source in a  
@For I also needed to put it in a hidden field or make it persistent,  
(b) using the value="..." idiom in a @For doesn't update the source,  
at least with arrays.

I think I would have figured out either of those pretty quickly. With  
both together, I ate literally hours over the last week or so.

Todd

On Feb 14, 2006, at 10:28 PM, Shawn Church wrote:

> Todd,
>
> For me, either carefully-controlled session-persisted properties or  
> hidden form values have worked best.  ListEdit might have helped  
> you in this case, but I've always found it to be pretty cumbersome,  
> and in the end all it really does is take care of setting up the  
> hidden fields for you.
>
> Shawn
>
> Todd O'Bryan wrote:
>>
>> On Feb 14, 2006, at 8:19 PM, Shawn Church wrote:
>>>
>>> Typically, pageBeginRender is invoked to initialize the page from  
>>> properties which (by this time) have already been set either by a  
>>> calling page, by a previous render, or by external page  
>>> initialization (by implementing IExternalPage).  After page  
>>> rendering is complete, the rendered response is sent to the  
>>> client.  The rewind phase is only invoked if a form is  
>>> submitted.  In this case, the form's listener method is invoked  
>>> (where you can do whatever you like with the submitted form  
>>> values), after which pageBeginRender will again be invoked to  
>>> render the page.
>>>
>>> Tapestry makes all of what you are trying to do very simple, but  
>>> it is important to understand exactly how it works.  Tapestry in  
>>> Action covers all of this for Tapestry 3, and Kent Tong's book is  
>>> a tremendous resource for Tapestry 4.
>>
>> There is a gotcha that I just spent the last week or so being very  
>> annoyed by (I'm still in Tapestry 3.0.3).
>>
>> I had a String[] of values. I was populating the array in  
>> pageBeginRender() and then passing the values so gotten to the  
>> next page in the form's listener.
>>
>> I tried
>>
>> <span jwcid="@base:For" source="ognl:vals" value="ognl:val">
>> <input type="text" jwcid="@TextField" value="ognl:val" />
>> </span>
>>
>> Unfortunately, vals[0]-vals[n] were not getting updated...they  
>> were exactly what they used to be. So I tried updating the array  
>> directly
>>
>> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
>> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
>> </span>
>>
>> This seemed to update the array correctly, but my handle to the  
>> array became null and any calls to getVals()[0] in the listener  
>> returned an NullPointerException. Now, vals was not a persistent  
>> property, so it was getting lost. I could either make it  
>> persistent (back button nightmares) or the following, which  
>> finally worked:
>>
>> <input type="hidden" jwcid="@Hidden" value="ognl:vals">
>> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
>> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
>> </span>
>>
>> Now I could access the array using getVals() in the listener  
>> method and it contained the updated values.
>>
>> Did I do something wrong or is this just way more convoluted than  
>> it should be? Or would ListEdit have saved me some trouble?
>>
>> Todd
>>
>> ---------------------------------------------------------------------
>> 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
>


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


Re: page state/cycle problem

Posted by Shawn Church <sh...@boxity.com>.
Todd,

For me, either carefully-controlled session-persisted properties or 
hidden form values have worked best.  ListEdit might have helped you in 
this case, but I've always found it to be pretty cumbersome, and in the 
end all it really does is take care of setting up the hidden fields for you.

Shawn

Todd O'Bryan wrote:
>
> On Feb 14, 2006, at 8:19 PM, Shawn Church wrote:
>>
>> Typically, pageBeginRender is invoked to initialize the page from 
>> properties which (by this time) have already been set either by a 
>> calling page, by a previous render, or by external page 
>> initialization (by implementing IExternalPage).  After page rendering 
>> is complete, the rendered response is sent to the client.  The rewind 
>> phase is only invoked if a form is submitted.  In this case, the 
>> form's listener method is invoked (where you can do whatever you like 
>> with the submitted form values), after which pageBeginRender will 
>> again be invoked to render the page.
>>
>> Tapestry makes all of what you are trying to do very simple, but it 
>> is important to understand exactly how it works.  Tapestry in Action 
>> covers all of this for Tapestry 3, and Kent Tong's book is a 
>> tremendous resource for Tapestry 4.
>
> There is a gotcha that I just spent the last week or so being very 
> annoyed by (I'm still in Tapestry 3.0.3).
>
> I had a String[] of values. I was populating the array in 
> pageBeginRender() and then passing the values so gotten to the next 
> page in the form's listener.
>
> I tried
>
> <span jwcid="@base:For" source="ognl:vals" value="ognl:val">
> <input type="text" jwcid="@TextField" value="ognl:val" />
> </span>
>
> Unfortunately, vals[0]-vals[n] were not getting updated...they were 
> exactly what they used to be. So I tried updating the array directly
>
> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
> </span>
>
> This seemed to update the array correctly, but my handle to the array 
> became null and any calls to getVals()[0] in the listener returned an 
> NullPointerException. Now, vals was not a persistent property, so it 
> was getting lost. I could either make it persistent (back button 
> nightmares) or the following, which finally worked:
>
> <input type="hidden" jwcid="@Hidden" value="ognl:vals">
> <span jwcid="@base:For" source="ognl:vals" index="ognl:i">
> <input type="text" jwcid="@TextField" value="ognl:vals[i]" />
> </span>
>
> Now I could access the array using getVals() in the listener method 
> and it contained the updated values.
>
> Did I do something wrong or is this just way more convoluted than it 
> should be? Or would ListEdit have saved me some trouble?
>
> Todd
>
> ---------------------------------------------------------------------
> 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


Re: page state/cycle problem

Posted by Todd O'Bryan <to...@mac.com>.
On Feb 14, 2006, at 8:19 PM, Shawn Church wrote:
>
> Typically, pageBeginRender is invoked to initialize the page from  
> properties which (by this time) have already been set either by a  
> calling page, by a previous render, or by external page  
> initialization (by implementing IExternalPage).  After page  
> rendering is complete, the rendered response is sent to the  
> client.  The rewind phase is only invoked if a form is submitted.   
> In this case, the form's listener method is invoked (where you can  
> do whatever you like with the submitted form values), after which  
> pageBeginRender will again be invoked to render the page.
>
> Tapestry makes all of what you are trying to do very simple, but it  
> is important to understand exactly how it works.  Tapestry in  
> Action covers all of this for Tapestry 3, and Kent Tong's book is a  
> tremendous resource for Tapestry 4.

There is a gotcha that I just spent the last week or so being very  
annoyed by (I'm still in Tapestry 3.0.3).

I had a String[] of values. I was populating the array in  
pageBeginRender() and then passing the values so gotten to the next  
page in the form's listener.

I tried

<span jwcid="@base:For" source="ognl:vals" value="ognl:val">
<input type="text" jwcid="@TextField" value="ognl:val" />
</span>

Unfortunately, vals[0]-vals[n] were not getting updated...they were  
exactly what they used to be. So I tried updating the array directly

<span jwcid="@base:For" source="ognl:vals" index="ognl:i">
<input type="text" jwcid="@TextField" value="ognl:vals[i]" />
</span>

This seemed to update the array correctly, but my handle to the array  
became null and any calls to getVals()[0] in the listener returned an  
NullPointerException. Now, vals was not a persistent property, so it  
was getting lost. I could either make it persistent (back button  
nightmares) or the following, which finally worked:

<input type="hidden" jwcid="@Hidden" value="ognl:vals">
<span jwcid="@base:For" source="ognl:vals" index="ognl:i">
<input type="text" jwcid="@TextField" value="ognl:vals[i]" />
</span>

Now I could access the array using getVals() in the listener method  
and it contained the updated values.

Did I do something wrong or is this just way more convoluted than it  
should be? Or would ListEdit have saved me some trouble?

Todd

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


Re: page state/cycle problem

Posted by Shawn Church <sh...@boxity.com>.
This is just an overview, so I have intentionally left out a lot of 
details, special cases, many additional features, etc.  However, this 
should give you a good starting point.

First of all, your pageBeginRender implementation should normally 
immediately return if in the rewind phase (unless you want to do 
something special such as logging page events, etc.).
      if( event.getRequestCycle().isRewinding())
         return;

It would be very unusual to ever use getRequest().getParameter().  
Tapestry page properties are set either by abstract or implemented bean 
methods (get / set / is).  If this page is being invoked from another 
page, page properties can be set from the calling page.  For example:

      TargetPage page = (TargetPage) cycle.getPage("TargetPage");
      page.setCrucualId(id);
      cycle.activate(page);

For Tapestry 3, abstract page properties must all be defined in your 
corresponding .page files as well.

If this page will be invoked directly from an outside application, or if 
you need the page to be bookmark-capable, or if the page for any other 
of various reasons needs to be invoked directly, then you can implement 
IExternalPage.  Page parameters will be passed directly to the 
activateExternalPage method where you are free to set any page 
properties prior to render.  The pageBeginRender method will be invoked 
after this as usual.

Typically, pageBeginRender is invoked to initialize the page from 
properties which (by this time) have already been set either by a 
calling page, by a previous render, or by external page initialization 
(by implementing IExternalPage).  After page rendering is complete, the 
rendered response is sent to the client.  The rewind phase is only 
invoked if a form is submitted.  In this case, the form's listener 
method is invoked (where you can do whatever you like with the submitted 
form values), after which pageBeginRender will again be invoked to 
render the page.

Tapestry makes all of what you are trying to do very simple, but it is 
important to understand exactly how it works.  Tapestry in Action covers 
all of this for Tapestry 3, and Kent Tong's book is a tremendous 
resource for Tapestry 4.

Shawn

Inge Solvoll wrote:
> I would like to provoke some debate on whether this is a good design pattern
> or not:
>
> public void pageBeginRender(PageEvent event) {
>   initState();
>   readItemsFromDatabase();
> }
>
> private Collection readItemsFromDatabase() {
>   return getDatabaseConnection().getItems();
> }
>
> private void initState() {
>   // Init all crucial page state here
> }
>
> My problem is that some ids in hidden inputs are needed by the initState
> method. These values are not available in the pageBeginRender method during
> rewind, because the Hidden components containing them haven't been rendered
> yet. I need this state information on a per-request basis, not per-session,
> so it is not possible to persist the page property. So far, I'm solving this
> by using good-old request parameters, and reading them the old servlet way
> in the pageBeginRender method like this:
>
> String crucialId = getRequest().getParameter("crucialId");
> page.setCrucialId(new Long(crucialId));
>
> I generally run into a lot of problems trying to find a good pattern for
> setting up data to fit with the RequestCycle. I have ended up doing the
> database reading in the pageBeginRender method, meaning that my data for the
> page is being read on every single rewind and render. I find it a bit hard
> to understand how to achieve this:
>
> On render:
> - Read data from database and set page properties
>
> On rewind:
> - Create non-null, empty, page properties ready to be populated from the
> request.
>
> My rewind step here often fails, and I don't see why. My page properties
> don't seem to be populated, when I leave them as, say, a non-null empty
> java.util.Collection to be populated with items from the request.
>
> Long and not very concentrated post, I actually don't know where to start
> here :)
>
> Inge
>
>   


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


Re: page state/cycle problem

Posted by Inge Solvoll <in...@gmail.com>.
I must have misunderstood how this works, no luck yet...

I created a squeezer for java.util.Vector that handles a collection of Item
(id, name) objects, and preserves the id property of the Item object. The
name properties should then be populated from request parameters (text
fields). The name properties are not populated with this approach. They are
however populated if I always initialize the items collection in
pageBeginRender().

The Vector-squeezer works, the page property items has the correct objects
with the correct ids set after rewind is complete, but not the name values
that I entered before submit...

I just don't get it... Maybe it's time to call it a day and celebrate the
weekend :)

Inge

On 2/17/06, Inge Solvoll <in...@gmail.com> wrote:
>
> Yes, that's correct, when I use this approach, the collection displays the
> correct content in the form listener. But:
>
> When I do this, the collection is serialized, causing a long Base64
> encoded string. I don't want that, becaus it may cause my html to become
> very large and too big to submit.
>
> I might be able to solve this by creating my own datasqueezer for
> collections.
>
> Anyway, thanks a lot, I see now why my collections are never
> auto-populated!
>
> Inge
>
> On 2/17/06, Todd O'Bryan <to...@mac.com> wrote:
> >
> > As long as your collection is Serializable, you don't need a custom
> > DataSqueezer. The problem is that Tapestry isn't saving the
> > information about the collection itself. This is the problem I was
> > having with my String[].
> >
> > Add a hidden field above your @For to save the items info:
> >
> > <input type="hidden" jwcid="@Hidden" value="ognl:items" />  <!-- I
> > don't think "ognl:" is necessary in 4.0, but I'm still using 3-->
> >
> > and getItems() will not return null in the listener.
> >
> > Todd
> >
> >
> > On Feb 17, 2006, at 4:52 AM, Inge Solvoll wrote:
> >
> > > Does there exist an example (vlib or similar) of a page that only gets
> >
> > > information from database on render, and that uses a custom
> > > datasqueezer and
> > > no db fetching for the rewind phase? My ideal design is that all known
> > > information in the rewind phase comes from request parameters, that
> > > way many
> > > synchronization issues can be avoided (request not matching content
> > > from
> > > database or other state).
> > >
> > > Inge
> > >
> > > On 2/16/06, Inge Solvoll < inge.tapestry@gmail.com> wrote:
> > >>
> > >> Yes, items is always null in pageBeginRender. If I remove the else
> > >> clause,
> > >> it is also null in the form listener. The else clause just
> > >> prevents null
> > >> values before render.
> > >>
> > >> I actually expect the values to be null in pageBeginRender, but I
> > >> expect
> > >> the collection to be populated in the end of the rewind, in the form
> > >> listener...
> > >>
> > >> Inge
> > >>
> > >> On 2/16/06, Ryan <cr...@gmail.com> wrote:
> > >>>
> > >>> It appears your problem is that getItems() will always be null in
> > >>> pageBeginRender because at that point parameters have not been
> > >>> bound.
> > >>> Try removing that else clause.
> > >>>
> > >>> Ryan
> > >>>
> > >>> On 2/16/06, Inge Solvoll < inge.tapestry@gmail.com> wrote:
> > >>>> I guess my (first) problem is simpler than this discussion, I'll
> > >>>> try
> > >>> to
> > >>>> explain:
> > >>>>
> > >>>> When I submit my form, I expect my page properties to be updated
> > >>> during
> > >>>> rewind automatically, without me having to write any java code
> > >>>> to make
> > >>> that
> > >>>> happen. But so far I haven't understood how this happens. I include
> > >>> here a
> > >>>> simple code example that I think illustrates my problem quite well.
> > >>> Why is
> > >>>> my collection always empty when the form listener is reached? If
> > >>>> I run
> > >>> the
> > >>>> initItems() method on both rewind and render, the values from the
> > >>> request
> > >>>> parameters are written into the page properties.
> > >>>>
> > >>>> My ultimate question is: Do I really have to get the items list
> > >>>> from
> > >>> the
> > >>>> database during rewind? Isn't there a way to avoid this, making
> > >>> tapestry
> > >>>> automatically build the items collection from the request
> > >>>> parameters?
> > >>> As I
> > >>>> wrote in another similar post on the list about DataSqueezer, I've
> > >>> tried
> > >>>> creating a datasqueezer for this, but the collection is still
> > >>>> showing
> > >>> up
> > >>>> empty.
> > >>>>
> > >>>> My HTML file:
> > >>>>
> > >>>>
> > >>> --------------------------------------------------------------------
> >
> > >>> ------
> > >>>>
> > >>>> <body jwcid="@Body">
> > >>>>
> > >>>> <form jwcid="@Form" listener="listener:formListener">
> > >>>>
> > >>>>     <span jwcid="@For" source="ognl:items"
> > >>>> value="ognl:currentItem">
> > >>>>       <span jwcid="@Insert" value="ognl: currentItem.name"/><br>
> > >>>>        <input type="text" jwcid="@TextField" value="ognl:
> > >>> currentItem.name"/>
> > >>>>        <br>
> > >>>>     </span>
> > >>>>
> > >>>> <input type="button" jwcid="@Submit" value="Submit form now"/>
> > >>>>
> > >>>> </form>
> > >>>> </body>
> > >>>>
> > >>>> -------------------------------------------------------------
> > >>>>
> > >>>> <page-specification class="Test">
> > >>>>     <property name="items"/>
> > >>>>     <property name="currentItem"/>
> > >>>> </page-specification>
> > >>>>
> > >>>> -------------------------------------------------------------
> > >>>>
> > >>>>
> > >>>> public abstract class Test extends BasePage implements
> > >>>> PageBeginRenderListener {
> > >>>>
> > >>>>   static Log log = LogFactory.getLog(Test.class);
> > >>>>
> > >>>>   public abstract Collection getItems();
> > >>>>   public abstract void setItems(Collection c);
> > >>>>
> > >>>>   public void pageBeginRender(PageEvent event) {
> > >>>>
> > >>>>     if (!getRequestCycle().isRewinding()) {
> > >>>>       initItems();
> > >>>>     }
> > >>>>     else {
> > >>>>       if (getItems() == null) {
> > >>>>         setItems(new Vector());
> > >>>>       }
> > >>>>     }
> > >>>>   }
> > >>>>
> > >>>>   public void formListener(IRequestCycle cycle) {
> > >>>>     Collection items = getItems();
> > >>>>     for (Iterator iter = items.iterator(); iter.hasNext();) {
> > >>>>       Item currItem = (Item) iter.next();
> > >>>>       log.debug("Current item id: " + currItem.getId() + ",
> > >>>> name: " +
> > >>>> currItem.getName());
> > >>>>     }
> > >>>>   }
> > >>>>
> > >>>>   private void initItems() {
> > >>>>     Collection items = new Vector();
> > >>>>
> > >>>>     items.add(new Item(new Long(1), "Item 1"));
> > >>>>     items.add(new Item(new Long(2), "Item 2"));
> > >>>>
> > >>>>     setItems(items);
> > >>>>   }
> > >>>> }
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>>> On 2/15/06, Ryan <cr...@gmail.com> wrote:
> > >>>>>
> > >>>>> You may want to look at the method prepareForRender(). This is the
> >
> > >>>>> method that handles binding of properties to form values. It is
> > >>>>> also
> > >>>>> called just before the component is rendered and in the order in
> > >>> which
> > >>>>> they are rendered on the page (where pageBeginRender is called
> > >>> before
> > >>>>> anything renders and is called in an undefined order). Also note
> > >>> that
> > >>>>> prepareForRender is not called if the component is not rendered
> > >>>>> (for
> > >>>>> instance if it is in an @Conditional that evaluates to false).
> > >>>>>
> > >>>>> I have received the best results from using pageBeginRender for
> > >>>>> initializing page properties that are static (ie known at all
> > >>>>> times
> > >>>>> during render, for instance a property select model property) and
> > >>>>> using prepareForRender in other times.
> > >>>>>
> > >>>>> Ryan
> > >>>>>
> > >>>>> On 2/14/06, Inge Solvoll < inge.tapestry@gmail.com> wrote:
> > >>>>>> I would like to provoke some debate on whether this is a good
> > >>> design
> > >>>>> pattern
> > >>>>>> or not:
> > >>>>>>
> > >>>>>> public void pageBeginRender(PageEvent event) {
> > >>>>>>   initState();
> > >>>>>>   readItemsFromDatabase();
> > >>>>>> }
> > >>>>>>
> > >>>>>> private Collection readItemsFromDatabase() {
> > >>>>>>   return getDatabaseConnection().getItems();
> > >>>>>> }
> > >>>>>>
> > >>>>>> private void initState() {
> > >>>>>>   // Init all crucial page state here
> > >>>>>> }
> > >>>>>>
> > >>>>>> My problem is that some ids in hidden inputs are needed by the
> > >>> initState
> > >>>>>> method. These values are not available in the pageBeginRender
> > >>> method
> > >>>>> during
> > >>>>>> rewind, because the Hidden components containing them haven't
> > >>>>>> been
> > >>>>> rendered
> > >>>>>> yet. I need this state information on a per-request basis, not
> > >>>>> per-session,
> > >>>>>> so it is not possible to persist the page property. So far, I'm
> > >>> solving
> > >>>>> this
> > >>>>>> by using good-old request parameters, and reading them the old
> > >>> servlet
> > >>>>> way
> > >>>>>> in the pageBeginRender method like this:
> > >>>>>>
> > >>>>>> String crucialId = getRequest().getParameter("crucialId");
> > >>>>>> page.setCrucialId(new Long(crucialId));
> > >>>>>>
> > >>>>>> I generally run into a lot of problems trying to find a good
> > >>> pattern for
> > >>>>>> setting up data to fit with the RequestCycle. I have ended up
> > >>> doing the
> > >>>>>> database reading in the pageBeginRender method, meaning that my
> > >>> data for
> > >>>>> the
> > >>>>>> page is being read on every single rewind and render. I find it a
> >
> > >>> bit
> > >>>>> hard
> > >>>>>> to understand how to achieve this:
> > >>>>>>
> > >>>>>> On render:
> > >>>>>> - Read data from database and set page properties
> > >>>>>>
> > >>>>>> On rewind:
> > >>>>>> - Create non-null, empty, page properties ready to be populated
> > >>> from the
> > >>>>>> request.
> > >>>>>>
> > >>>>>> My rewind step here often fails, and I don't see why. My page
> > >>> properties
> > >>>>>> don't seem to be populated, when I leave them as, say, a non-null
> >
> > >>> empty
> > >>>>>> java.util.Collection to be populated with items from the request.
> > >>>>>>
> > >>>>>> Long and not very concentrated post, I actually don't know where
> > >>> to
> > >>>>> start
> > >>>>>> here :)
> > >>>>>>
> > >>>>>> Inge
> > >>>>>>
> > >>>>>>
> > >>>>>
> > >>>>>
> > >>> --------------------------------------------------------------------
> > >>> -
> > >>>>> 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
> > >>>
> > >>>
> > >>
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> >
> >
>

Re: page state/cycle problem

Posted by Inge Solvoll <in...@gmail.com>.
Yes, that's correct, when I use this approach, the collection displays the
correct content in the form listener. But:

When I do this, the collection is serialized, causing a long Base64 encoded
string. I don't want that, becaus it may cause my html to become very large
and too big to submit.

I might be able to solve this by creating my own datasqueezer for
collections.

Anyway, thanks a lot, I see now why my collections are never auto-populated!

Inge

On 2/17/06, Todd O'Bryan <to...@mac.com> wrote:
>
> As long as your collection is Serializable, you don't need a custom
> DataSqueezer. The problem is that Tapestry isn't saving the
> information about the collection itself. This is the problem I was
> having with my String[].
>
> Add a hidden field above your @For to save the items info:
>
> <input type="hidden" jwcid="@Hidden" value="ognl:items" />  <!-- I
> don't think "ognl:" is necessary in 4.0, but I'm still using 3-->
>
> and getItems() will not return null in the listener.
>
> Todd
>
>
> On Feb 17, 2006, at 4:52 AM, Inge Solvoll wrote:
>
> > Does there exist an example (vlib or similar) of a page that only gets
> > information from database on render, and that uses a custom
> > datasqueezer and
> > no db fetching for the rewind phase? My ideal design is that all known
> > information in the rewind phase comes from request parameters, that
> > way many
> > synchronization issues can be avoided (request not matching content
> > from
> > database or other state).
> >
> > Inge
> >
> > On 2/16/06, Inge Solvoll <in...@gmail.com> wrote:
> >>
> >> Yes, items is always null in pageBeginRender. If I remove the else
> >> clause,
> >> it is also null in the form listener. The else clause just
> >> prevents null
> >> values before render.
> >>
> >> I actually expect the values to be null in pageBeginRender, but I
> >> expect
> >> the collection to be populated in the end of the rewind, in the form
> >> listener...
> >>
> >> Inge
> >>
> >> On 2/16/06, Ryan <cr...@gmail.com> wrote:
> >>>
> >>> It appears your problem is that getItems() will always be null in
> >>> pageBeginRender because at that point parameters have not been
> >>> bound.
> >>> Try removing that else clause.
> >>>
> >>> Ryan
> >>>
> >>> On 2/16/06, Inge Solvoll < inge.tapestry@gmail.com> wrote:
> >>>> I guess my (first) problem is simpler than this discussion, I'll
> >>>> try
> >>> to
> >>>> explain:
> >>>>
> >>>> When I submit my form, I expect my page properties to be updated
> >>> during
> >>>> rewind automatically, without me having to write any java code
> >>>> to make
> >>> that
> >>>> happen. But so far I haven't understood how this happens. I include
> >>> here a
> >>>> simple code example that I think illustrates my problem quite well.
> >>> Why is
> >>>> my collection always empty when the form listener is reached? If
> >>>> I run
> >>> the
> >>>> initItems() method on both rewind and render, the values from the
> >>> request
> >>>> parameters are written into the page properties.
> >>>>
> >>>> My ultimate question is: Do I really have to get the items list
> >>>> from
> >>> the
> >>>> database during rewind? Isn't there a way to avoid this, making
> >>> tapestry
> >>>> automatically build the items collection from the request
> >>>> parameters?
> >>> As I
> >>>> wrote in another similar post on the list about DataSqueezer, I've
> >>> tried
> >>>> creating a datasqueezer for this, but the collection is still
> >>>> showing
> >>> up
> >>>> empty.
> >>>>
> >>>> My HTML file:
> >>>>
> >>>>
> >>> --------------------------------------------------------------------
> >>> ------
> >>>>
> >>>> <body jwcid="@Body">
> >>>>
> >>>> <form jwcid="@Form" listener="listener:formListener">
> >>>>
> >>>>     <span jwcid="@For" source="ognl:items"
> >>>> value="ognl:currentItem">
> >>>>       <span jwcid="@Insert" value="ognl:currentItem.name"/><br>
> >>>>        <input type="text" jwcid="@TextField" value="ognl:
> >>> currentItem.name"/>
> >>>>        <br>
> >>>>     </span>
> >>>>
> >>>> <input type="button" jwcid="@Submit" value="Submit form now"/>
> >>>>
> >>>> </form>
> >>>> </body>
> >>>>
> >>>> -------------------------------------------------------------
> >>>>
> >>>> <page-specification class="Test">
> >>>>     <property name="items"/>
> >>>>     <property name="currentItem"/>
> >>>> </page-specification>
> >>>>
> >>>> -------------------------------------------------------------
> >>>>
> >>>>
> >>>> public abstract class Test extends BasePage implements
> >>>> PageBeginRenderListener {
> >>>>
> >>>>   static Log log = LogFactory.getLog(Test.class);
> >>>>
> >>>>   public abstract Collection getItems();
> >>>>   public abstract void setItems(Collection c);
> >>>>
> >>>>   public void pageBeginRender(PageEvent event) {
> >>>>
> >>>>     if (!getRequestCycle().isRewinding()) {
> >>>>       initItems();
> >>>>     }
> >>>>     else {
> >>>>       if (getItems() == null) {
> >>>>         setItems(new Vector());
> >>>>       }
> >>>>     }
> >>>>   }
> >>>>
> >>>>   public void formListener(IRequestCycle cycle) {
> >>>>     Collection items = getItems();
> >>>>     for (Iterator iter = items.iterator(); iter.hasNext();) {
> >>>>       Item currItem = (Item) iter.next();
> >>>>       log.debug("Current item id: " + currItem.getId() + ",
> >>>> name: " +
> >>>> currItem.getName());
> >>>>     }
> >>>>   }
> >>>>
> >>>>   private void initItems() {
> >>>>     Collection items = new Vector();
> >>>>
> >>>>     items.add(new Item(new Long(1), "Item 1"));
> >>>>     items.add(new Item(new Long(2), "Item 2"));
> >>>>
> >>>>     setItems(items);
> >>>>   }
> >>>> }
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>> On 2/15/06, Ryan <cr...@gmail.com> wrote:
> >>>>>
> >>>>> You may want to look at the method prepareForRender(). This is the
> >>>>> method that handles binding of properties to form values. It is
> >>>>> also
> >>>>> called just before the component is rendered and in the order in
> >>> which
> >>>>> they are rendered on the page (where pageBeginRender is called
> >>> before
> >>>>> anything renders and is called in an undefined order). Also note
> >>> that
> >>>>> prepareForRender is not called if the component is not rendered
> >>>>> (for
> >>>>> instance if it is in an @Conditional that evaluates to false).
> >>>>>
> >>>>> I have received the best results from using pageBeginRender for
> >>>>> initializing page properties that are static (ie known at all
> >>>>> times
> >>>>> during render, for instance a property select model property) and
> >>>>> using prepareForRender in other times.
> >>>>>
> >>>>> Ryan
> >>>>>
> >>>>> On 2/14/06, Inge Solvoll <in...@gmail.com> wrote:
> >>>>>> I would like to provoke some debate on whether this is a good
> >>> design
> >>>>> pattern
> >>>>>> or not:
> >>>>>>
> >>>>>> public void pageBeginRender(PageEvent event) {
> >>>>>>   initState();
> >>>>>>   readItemsFromDatabase();
> >>>>>> }
> >>>>>>
> >>>>>> private Collection readItemsFromDatabase() {
> >>>>>>   return getDatabaseConnection().getItems();
> >>>>>> }
> >>>>>>
> >>>>>> private void initState() {
> >>>>>>   // Init all crucial page state here
> >>>>>> }
> >>>>>>
> >>>>>> My problem is that some ids in hidden inputs are needed by the
> >>> initState
> >>>>>> method. These values are not available in the pageBeginRender
> >>> method
> >>>>> during
> >>>>>> rewind, because the Hidden components containing them haven't
> >>>>>> been
> >>>>> rendered
> >>>>>> yet. I need this state information on a per-request basis, not
> >>>>> per-session,
> >>>>>> so it is not possible to persist the page property. So far, I'm
> >>> solving
> >>>>> this
> >>>>>> by using good-old request parameters, and reading them the old
> >>> servlet
> >>>>> way
> >>>>>> in the pageBeginRender method like this:
> >>>>>>
> >>>>>> String crucialId = getRequest().getParameter("crucialId");
> >>>>>> page.setCrucialId(new Long(crucialId));
> >>>>>>
> >>>>>> I generally run into a lot of problems trying to find a good
> >>> pattern for
> >>>>>> setting up data to fit with the RequestCycle. I have ended up
> >>> doing the
> >>>>>> database reading in the pageBeginRender method, meaning that my
> >>> data for
> >>>>> the
> >>>>>> page is being read on every single rewind and render. I find it a
> >>> bit
> >>>>> hard
> >>>>>> to understand how to achieve this:
> >>>>>>
> >>>>>> On render:
> >>>>>> - Read data from database and set page properties
> >>>>>>
> >>>>>> On rewind:
> >>>>>> - Create non-null, empty, page properties ready to be populated
> >>> from the
> >>>>>> request.
> >>>>>>
> >>>>>> My rewind step here often fails, and I don't see why. My page
> >>> properties
> >>>>>> don't seem to be populated, when I leave them as, say, a non-null
> >>> empty
> >>>>>> java.util.Collection to be populated with items from the request.
> >>>>>>
> >>>>>> Long and not very concentrated post, I actually don't know where
> >>> to
> >>>>> start
> >>>>>> here :)
> >>>>>>
> >>>>>> Inge
> >>>>>>
> >>>>>>
> >>>>>
> >>>>>
> >>> --------------------------------------------------------------------
> >>> -
> >>>>> 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
> >>>
> >>>
> >>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>
>

Re: page state/cycle problem

Posted by Todd O'Bryan <to...@mac.com>.
As long as your collection is Serializable, you don't need a custom  
DataSqueezer. The problem is that Tapestry isn't saving the  
information about the collection itself. This is the problem I was  
having with my String[].

Add a hidden field above your @For to save the items info:

<input type="hidden" jwcid="@Hidden" value="ognl:items" />  <!-- I  
don't think "ognl:" is necessary in 4.0, but I'm still using 3-->

and getItems() will not return null in the listener.

Todd


On Feb 17, 2006, at 4:52 AM, Inge Solvoll wrote:

> Does there exist an example (vlib or similar) of a page that only gets
> information from database on render, and that uses a custom  
> datasqueezer and
> no db fetching for the rewind phase? My ideal design is that all known
> information in the rewind phase comes from request parameters, that  
> way many
> synchronization issues can be avoided (request not matching content  
> from
> database or other state).
>
> Inge
>
> On 2/16/06, Inge Solvoll <in...@gmail.com> wrote:
>>
>> Yes, items is always null in pageBeginRender. If I remove the else  
>> clause,
>> it is also null in the form listener. The else clause just  
>> prevents null
>> values before render.
>>
>> I actually expect the values to be null in pageBeginRender, but I  
>> expect
>> the collection to be populated in the end of the rewind, in the form
>> listener...
>>
>> Inge
>>
>> On 2/16/06, Ryan <cr...@gmail.com> wrote:
>>>
>>> It appears your problem is that getItems() will always be null in
>>> pageBeginRender because at that point parameters have not been  
>>> bound.
>>> Try removing that else clause.
>>>
>>> Ryan
>>>
>>> On 2/16/06, Inge Solvoll < inge.tapestry@gmail.com> wrote:
>>>> I guess my (first) problem is simpler than this discussion, I'll  
>>>> try
>>> to
>>>> explain:
>>>>
>>>> When I submit my form, I expect my page properties to be updated
>>> during
>>>> rewind automatically, without me having to write any java code  
>>>> to make
>>> that
>>>> happen. But so far I haven't understood how this happens. I include
>>> here a
>>>> simple code example that I think illustrates my problem quite well.
>>> Why is
>>>> my collection always empty when the form listener is reached? If  
>>>> I run
>>> the
>>>> initItems() method on both rewind and render, the values from the
>>> request
>>>> parameters are written into the page properties.
>>>>
>>>> My ultimate question is: Do I really have to get the items list  
>>>> from
>>> the
>>>> database during rewind? Isn't there a way to avoid this, making
>>> tapestry
>>>> automatically build the items collection from the request  
>>>> parameters?
>>> As I
>>>> wrote in another similar post on the list about DataSqueezer, I've
>>> tried
>>>> creating a datasqueezer for this, but the collection is still  
>>>> showing
>>> up
>>>> empty.
>>>>
>>>> My HTML file:
>>>>
>>>>
>>> -------------------------------------------------------------------- 
>>> ------
>>>>
>>>> <body jwcid="@Body">
>>>>
>>>> <form jwcid="@Form" listener="listener:formListener">
>>>>
>>>>     <span jwcid="@For" source="ognl:items"  
>>>> value="ognl:currentItem">
>>>>       <span jwcid="@Insert" value="ognl:currentItem.name"/><br>
>>>>        <input type="text" jwcid="@TextField" value="ognl:
>>> currentItem.name"/>
>>>>        <br>
>>>>     </span>
>>>>
>>>> <input type="button" jwcid="@Submit" value="Submit form now"/>
>>>>
>>>> </form>
>>>> </body>
>>>>
>>>> -------------------------------------------------------------
>>>>
>>>> <page-specification class="Test">
>>>>     <property name="items"/>
>>>>     <property name="currentItem"/>
>>>> </page-specification>
>>>>
>>>> -------------------------------------------------------------
>>>>
>>>>
>>>> public abstract class Test extends BasePage implements
>>>> PageBeginRenderListener {
>>>>
>>>>   static Log log = LogFactory.getLog(Test.class);
>>>>
>>>>   public abstract Collection getItems();
>>>>   public abstract void setItems(Collection c);
>>>>
>>>>   public void pageBeginRender(PageEvent event) {
>>>>
>>>>     if (!getRequestCycle().isRewinding()) {
>>>>       initItems();
>>>>     }
>>>>     else {
>>>>       if (getItems() == null) {
>>>>         setItems(new Vector());
>>>>       }
>>>>     }
>>>>   }
>>>>
>>>>   public void formListener(IRequestCycle cycle) {
>>>>     Collection items = getItems();
>>>>     for (Iterator iter = items.iterator(); iter.hasNext();) {
>>>>       Item currItem = (Item) iter.next();
>>>>       log.debug("Current item id: " + currItem.getId() + ",  
>>>> name: " +
>>>> currItem.getName());
>>>>     }
>>>>   }
>>>>
>>>>   private void initItems() {
>>>>     Collection items = new Vector();
>>>>
>>>>     items.add(new Item(new Long(1), "Item 1"));
>>>>     items.add(new Item(new Long(2), "Item 2"));
>>>>
>>>>     setItems(items);
>>>>   }
>>>> }
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On 2/15/06, Ryan <cr...@gmail.com> wrote:
>>>>>
>>>>> You may want to look at the method prepareForRender(). This is the
>>>>> method that handles binding of properties to form values. It is  
>>>>> also
>>>>> called just before the component is rendered and in the order in
>>> which
>>>>> they are rendered on the page (where pageBeginRender is called
>>> before
>>>>> anything renders and is called in an undefined order). Also note
>>> that
>>>>> prepareForRender is not called if the component is not rendered  
>>>>> (for
>>>>> instance if it is in an @Conditional that evaluates to false).
>>>>>
>>>>> I have received the best results from using pageBeginRender for
>>>>> initializing page properties that are static (ie known at all  
>>>>> times
>>>>> during render, for instance a property select model property) and
>>>>> using prepareForRender in other times.
>>>>>
>>>>> Ryan
>>>>>
>>>>> On 2/14/06, Inge Solvoll <in...@gmail.com> wrote:
>>>>>> I would like to provoke some debate on whether this is a good
>>> design
>>>>> pattern
>>>>>> or not:
>>>>>>
>>>>>> public void pageBeginRender(PageEvent event) {
>>>>>>   initState();
>>>>>>   readItemsFromDatabase();
>>>>>> }
>>>>>>
>>>>>> private Collection readItemsFromDatabase() {
>>>>>>   return getDatabaseConnection().getItems();
>>>>>> }
>>>>>>
>>>>>> private void initState() {
>>>>>>   // Init all crucial page state here
>>>>>> }
>>>>>>
>>>>>> My problem is that some ids in hidden inputs are needed by the
>>> initState
>>>>>> method. These values are not available in the pageBeginRender
>>> method
>>>>> during
>>>>>> rewind, because the Hidden components containing them haven't  
>>>>>> been
>>>>> rendered
>>>>>> yet. I need this state information on a per-request basis, not
>>>>> per-session,
>>>>>> so it is not possible to persist the page property. So far, I'm
>>> solving
>>>>> this
>>>>>> by using good-old request parameters, and reading them the old
>>> servlet
>>>>> way
>>>>>> in the pageBeginRender method like this:
>>>>>>
>>>>>> String crucialId = getRequest().getParameter("crucialId");
>>>>>> page.setCrucialId(new Long(crucialId));
>>>>>>
>>>>>> I generally run into a lot of problems trying to find a good
>>> pattern for
>>>>>> setting up data to fit with the RequestCycle. I have ended up
>>> doing the
>>>>>> database reading in the pageBeginRender method, meaning that my
>>> data for
>>>>> the
>>>>>> page is being read on every single rewind and render. I find it a
>>> bit
>>>>> hard
>>>>>> to understand how to achieve this:
>>>>>>
>>>>>> On render:
>>>>>> - Read data from database and set page properties
>>>>>>
>>>>>> On rewind:
>>>>>> - Create non-null, empty, page properties ready to be populated
>>> from the
>>>>>> request.
>>>>>>
>>>>>> My rewind step here often fails, and I don't see why. My page
>>> properties
>>>>>> don't seem to be populated, when I leave them as, say, a non-null
>>> empty
>>>>>> java.util.Collection to be populated with items from the request.
>>>>>>
>>>>>> Long and not very concentrated post, I actually don't know where
>>> to
>>>>> start
>>>>>> here :)
>>>>>>
>>>>>> Inge
>>>>>>
>>>>>>
>>>>>
>>>>>
>>> -------------------------------------------------------------------- 
>>> -
>>>>> 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
>>>
>>>
>>


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


Re: page state/cycle problem

Posted by Inge Solvoll <in...@gmail.com>.
Does there exist an example (vlib or similar) of a page that only gets
information from database on render, and that uses a custom datasqueezer and
no db fetching for the rewind phase? My ideal design is that all known
information in the rewind phase comes from request parameters, that way many
synchronization issues can be avoided (request not matching content from
database or other state).

Inge

On 2/16/06, Inge Solvoll <in...@gmail.com> wrote:
>
> Yes, items is always null in pageBeginRender. If I remove the else clause,
> it is also null in the form listener. The else clause just prevents null
> values before render.
>
> I actually expect the values to be null in pageBeginRender, but I expect
> the collection to be populated in the end of the rewind, in the form
> listener...
>
> Inge
>
> On 2/16/06, Ryan <cr...@gmail.com> wrote:
> >
> > It appears your problem is that getItems() will always be null in
> > pageBeginRender because at that point parameters have not been bound.
> > Try removing that else clause.
> >
> > Ryan
> >
> > On 2/16/06, Inge Solvoll < inge.tapestry@gmail.com> wrote:
> > > I guess my (first) problem is simpler than this discussion, I'll try
> > to
> > > explain:
> > >
> > > When I submit my form, I expect my page properties to be updated
> > during
> > > rewind automatically, without me having to write any java code to make
> > that
> > > happen. But so far I haven't understood how this happens. I include
> > here a
> > > simple code example that I think illustrates my problem quite well.
> > Why is
> > > my collection always empty when the form listener is reached? If I run
> > the
> > > initItems() method on both rewind and render, the values from the
> > request
> > > parameters are written into the page properties.
> > >
> > > My ultimate question is: Do I really have to get the items list from
> > the
> > > database during rewind? Isn't there a way to avoid this, making
> > tapestry
> > > automatically build the items collection from the request parameters?
> > As I
> > > wrote in another similar post on the list about DataSqueezer, I've
> > tried
> > > creating a datasqueezer for this, but the collection is still showing
> > up
> > > empty.
> > >
> > > My HTML file:
> > >
> > >
> > --------------------------------------------------------------------------
> > >
> > > <body jwcid="@Body">
> > >
> > > <form jwcid="@Form" listener="listener:formListener">
> > >
> > >     <span jwcid="@For" source="ognl:items" value="ognl:currentItem">
> > >       <span jwcid="@Insert" value="ognl:currentItem.name"/><br>
> > >        <input type="text" jwcid="@TextField" value="ognl:
> > currentItem.name"/>
> > >        <br>
> > >     </span>
> > >
> > > <input type="button" jwcid="@Submit" value="Submit form now"/>
> > >
> > > </form>
> > > </body>
> > >
> > > -------------------------------------------------------------
> > >
> > > <page-specification class="Test">
> > >     <property name="items"/>
> > >     <property name="currentItem"/>
> > > </page-specification>
> > >
> > > -------------------------------------------------------------
> > >
> > >
> > > public abstract class Test extends BasePage implements
> > > PageBeginRenderListener {
> > >
> > >   static Log log = LogFactory.getLog(Test.class);
> > >
> > >   public abstract Collection getItems();
> > >   public abstract void setItems(Collection c);
> > >
> > >   public void pageBeginRender(PageEvent event) {
> > >
> > >     if (!getRequestCycle().isRewinding()) {
> > >       initItems();
> > >     }
> > >     else {
> > >       if (getItems() == null) {
> > >         setItems(new Vector());
> > >       }
> > >     }
> > >   }
> > >
> > >   public void formListener(IRequestCycle cycle) {
> > >     Collection items = getItems();
> > >     for (Iterator iter = items.iterator(); iter.hasNext();) {
> > >       Item currItem = (Item) iter.next();
> > >       log.debug("Current item id: " + currItem.getId() + ", name: " +
> > > currItem.getName());
> > >     }
> > >   }
> > >
> > >   private void initItems() {
> > >     Collection items = new Vector();
> > >
> > >     items.add(new Item(new Long(1), "Item 1"));
> > >     items.add(new Item(new Long(2), "Item 2"));
> > >
> > >     setItems(items);
> > >   }
> > > }
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > > On 2/15/06, Ryan <cr...@gmail.com> wrote:
> > > >
> > > > You may want to look at the method prepareForRender(). This is the
> > > > method that handles binding of properties to form values. It is also
> > > > called just before the component is rendered and in the order in
> > which
> > > > they are rendered on the page (where pageBeginRender is called
> > before
> > > > anything renders and is called in an undefined order). Also note
> > that
> > > > prepareForRender is not called if the component is not rendered (for
> > > > instance if it is in an @Conditional that evaluates to false).
> > > >
> > > > I have received the best results from using pageBeginRender for
> > > > initializing page properties that are static (ie known at all times
> > > > during render, for instance a property select model property) and
> > > > using prepareForRender in other times.
> > > >
> > > > Ryan
> > > >
> > > > On 2/14/06, Inge Solvoll <in...@gmail.com> wrote:
> > > > > I would like to provoke some debate on whether this is a good
> > design
> > > > pattern
> > > > > or not:
> > > > >
> > > > > public void pageBeginRender(PageEvent event) {
> > > > >   initState();
> > > > >   readItemsFromDatabase();
> > > > > }
> > > > >
> > > > > private Collection readItemsFromDatabase() {
> > > > >   return getDatabaseConnection().getItems();
> > > > > }
> > > > >
> > > > > private void initState() {
> > > > >   // Init all crucial page state here
> > > > > }
> > > > >
> > > > > My problem is that some ids in hidden inputs are needed by the
> > initState
> > > > > method. These values are not available in the pageBeginRender
> > method
> > > > during
> > > > > rewind, because the Hidden components containing them haven't been
> > > > rendered
> > > > > yet. I need this state information on a per-request basis, not
> > > > per-session,
> > > > > so it is not possible to persist the page property. So far, I'm
> > solving
> > > > this
> > > > > by using good-old request parameters, and reading them the old
> > servlet
> > > > way
> > > > > in the pageBeginRender method like this:
> > > > >
> > > > > String crucialId = getRequest().getParameter("crucialId");
> > > > > page.setCrucialId(new Long(crucialId));
> > > > >
> > > > > I generally run into a lot of problems trying to find a good
> > pattern for
> > > > > setting up data to fit with the RequestCycle. I have ended up
> > doing the
> > > > > database reading in the pageBeginRender method, meaning that my
> > data for
> > > > the
> > > > > page is being read on every single rewind and render. I find it a
> > bit
> > > > hard
> > > > > to understand how to achieve this:
> > > > >
> > > > > On render:
> > > > > - Read data from database and set page properties
> > > > >
> > > > > On rewind:
> > > > > - Create non-null, empty, page properties ready to be populated
> > from the
> > > > > request.
> > > > >
> > > > > My rewind step here often fails, and I don't see why. My page
> > properties
> > > > > don't seem to be populated, when I leave them as, say, a non-null
> > empty
> > > > > java.util.Collection to be populated with items from the request.
> > > > >
> > > > > Long and not very concentrated post, I actually don't know where
> > to
> > > > start
> > > > > here :)
> > > > >
> > > > > Inge
> > > > >
> > > > >
> > > >
> > > >
> > ---------------------------------------------------------------------
> > > > 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
> >
> >
>

Re: page state/cycle problem

Posted by Inge Solvoll <in...@gmail.com>.
Yes, items is always null in pageBeginRender. If I remove the else clause,
it is also null in the form listener. The else clause just prevents null
values before render.

I actually expect the values to be null in pageBeginRender, but I expect the
collection to be populated in the end of the rewind, in the form listener...

Inge

On 2/16/06, Ryan <cr...@gmail.com> wrote:
>
> It appears your problem is that getItems() will always be null in
> pageBeginRender because at that point parameters have not been bound.
> Try removing that else clause.
>
> Ryan
>
> On 2/16/06, Inge Solvoll <in...@gmail.com> wrote:
> > I guess my (first) problem is simpler than this discussion, I'll try to
> > explain:
> >
> > When I submit my form, I expect my page properties to be updated during
> > rewind automatically, without me having to write any java code to make
> that
> > happen. But so far I haven't understood how this happens. I include here
> a
> > simple code example that I think illustrates my problem quite well. Why
> is
> > my collection always empty when the form listener is reached? If I run
> the
> > initItems() method on both rewind and render, the values from the
> request
> > parameters are written into the page properties.
> >
> > My ultimate question is: Do I really have to get the items list from the
> > database during rewind? Isn't there a way to avoid this, making tapestry
> > automatically build the items collection from the request parameters? As
> I
> > wrote in another similar post on the list about DataSqueezer, I've tried
> > creating a datasqueezer for this, but the collection is still showing up
> > empty.
> >
> > My HTML file:
> >
> >
> --------------------------------------------------------------------------
> >
> > <body jwcid="@Body">
> >
> > <form jwcid="@Form" listener="listener:formListener">
> >
> >     <span jwcid="@For" source="ognl:items" value="ognl:currentItem">
> >       <span jwcid="@Insert" value="ognl:currentItem.name"/><br>
> >        <input type="text" jwcid="@TextField" value="ognl:
> currentItem.name"/>
> >        <br>
> >     </span>
> >
> > <input type="button" jwcid="@Submit" value="Submit form now"/>
> >
> > </form>
> > </body>
> >
> > -------------------------------------------------------------
> >
> > <page-specification class="Test">
> >     <property name="items"/>
> >     <property name="currentItem"/>
> > </page-specification>
> >
> > -------------------------------------------------------------
> >
> >
> > public abstract class Test extends BasePage implements
> > PageBeginRenderListener {
> >
> >   static Log log = LogFactory.getLog(Test.class);
> >
> >   public abstract Collection getItems();
> >   public abstract void setItems(Collection c);
> >
> >   public void pageBeginRender(PageEvent event) {
> >
> >     if (!getRequestCycle().isRewinding()) {
> >       initItems();
> >     }
> >     else {
> >       if (getItems() == null) {
> >         setItems(new Vector());
> >       }
> >     }
> >   }
> >
> >   public void formListener(IRequestCycle cycle) {
> >     Collection items = getItems();
> >     for (Iterator iter = items.iterator(); iter.hasNext();) {
> >       Item currItem = (Item) iter.next();
> >       log.debug("Current item id: " + currItem.getId() + ", name: " +
> > currItem.getName());
> >     }
> >   }
> >
> >   private void initItems() {
> >     Collection items = new Vector();
> >
> >     items.add(new Item(new Long(1), "Item 1"));
> >     items.add(new Item(new Long(2), "Item 2"));
> >
> >     setItems(items);
> >   }
> > }
> >
> >
> >
> >
> >
> >
> >
> > On 2/15/06, Ryan <cr...@gmail.com> wrote:
> > >
> > > You may want to look at the method prepareForRender(). This is the
> > > method that handles binding of properties to form values. It is also
> > > called just before the component is rendered and in the order in which
> > > they are rendered on the page (where pageBeginRender is called before
> > > anything renders and is called in an undefined order). Also note that
> > > prepareForRender is not called if the component is not rendered (for
> > > instance if it is in an @Conditional that evaluates to false).
> > >
> > > I have received the best results from using pageBeginRender for
> > > initializing page properties that are static (ie known at all times
> > > during render, for instance a property select model property) and
> > > using prepareForRender in other times.
> > >
> > > Ryan
> > >
> > > On 2/14/06, Inge Solvoll <in...@gmail.com> wrote:
> > > > I would like to provoke some debate on whether this is a good design
> > > pattern
> > > > or not:
> > > >
> > > > public void pageBeginRender(PageEvent event) {
> > > >   initState();
> > > >   readItemsFromDatabase();
> > > > }
> > > >
> > > > private Collection readItemsFromDatabase() {
> > > >   return getDatabaseConnection().getItems();
> > > > }
> > > >
> > > > private void initState() {
> > > >   // Init all crucial page state here
> > > > }
> > > >
> > > > My problem is that some ids in hidden inputs are needed by the
> initState
> > > > method. These values are not available in the pageBeginRender method
> > > during
> > > > rewind, because the Hidden components containing them haven't been
> > > rendered
> > > > yet. I need this state information on a per-request basis, not
> > > per-session,
> > > > so it is not possible to persist the page property. So far, I'm
> solving
> > > this
> > > > by using good-old request parameters, and reading them the old
> servlet
> > > way
> > > > in the pageBeginRender method like this:
> > > >
> > > > String crucialId = getRequest().getParameter("crucialId");
> > > > page.setCrucialId(new Long(crucialId));
> > > >
> > > > I generally run into a lot of problems trying to find a good pattern
> for
> > > > setting up data to fit with the RequestCycle. I have ended up doing
> the
> > > > database reading in the pageBeginRender method, meaning that my data
> for
> > > the
> > > > page is being read on every single rewind and render. I find it a
> bit
> > > hard
> > > > to understand how to achieve this:
> > > >
> > > > On render:
> > > > - Read data from database and set page properties
> > > >
> > > > On rewind:
> > > > - Create non-null, empty, page properties ready to be populated from
> the
> > > > request.
> > > >
> > > > My rewind step here often fails, and I don't see why. My page
> properties
> > > > don't seem to be populated, when I leave them as, say, a non-null
> empty
> > > > java.util.Collection to be populated with items from the request.
> > > >
> > > > Long and not very concentrated post, I actually don't know where to
> > > start
> > > > here :)
> > > >
> > > > Inge
> > > >
> > > >
> > >
> > > ---------------------------------------------------------------------
> > > 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
>
>

Re: page state/cycle problem

Posted by Ryan <cr...@gmail.com>.
It appears your problem is that getItems() will always be null in
pageBeginRender because at that point parameters have not been bound.
Try removing that else clause.

Ryan

On 2/16/06, Inge Solvoll <in...@gmail.com> wrote:
> I guess my (first) problem is simpler than this discussion, I'll try to
> explain:
>
> When I submit my form, I expect my page properties to be updated during
> rewind automatically, without me having to write any java code to make that
> happen. But so far I haven't understood how this happens. I include here a
> simple code example that I think illustrates my problem quite well. Why is
> my collection always empty when the form listener is reached? If I run the
> initItems() method on both rewind and render, the values from the request
> parameters are written into the page properties.
>
> My ultimate question is: Do I really have to get the items list from the
> database during rewind? Isn't there a way to avoid this, making tapestry
> automatically build the items collection from the request parameters? As I
> wrote in another similar post on the list about DataSqueezer, I've tried
> creating a datasqueezer for this, but the collection is still showing up
> empty.
>
> My HTML file:
>
> --------------------------------------------------------------------------
>
> <body jwcid="@Body">
>
> <form jwcid="@Form" listener="listener:formListener">
>
>     <span jwcid="@For" source="ognl:items" value="ognl:currentItem">
>       <span jwcid="@Insert" value="ognl:currentItem.name"/><br>
>        <input type="text" jwcid="@TextField" value="ognl:currentItem.name"/>
>        <br>
>     </span>
>
> <input type="button" jwcid="@Submit" value="Submit form now"/>
>
> </form>
> </body>
>
> -------------------------------------------------------------
>
> <page-specification class="Test">
>     <property name="items"/>
>     <property name="currentItem"/>
> </page-specification>
>
> -------------------------------------------------------------
>
>
> public abstract class Test extends BasePage implements
> PageBeginRenderListener {
>
>   static Log log = LogFactory.getLog(Test.class);
>
>   public abstract Collection getItems();
>   public abstract void setItems(Collection c);
>
>   public void pageBeginRender(PageEvent event) {
>
>     if (!getRequestCycle().isRewinding()) {
>       initItems();
>     }
>     else {
>       if (getItems() == null) {
>         setItems(new Vector());
>       }
>     }
>   }
>
>   public void formListener(IRequestCycle cycle) {
>     Collection items = getItems();
>     for (Iterator iter = items.iterator(); iter.hasNext();) {
>       Item currItem = (Item) iter.next();
>       log.debug("Current item id: " + currItem.getId() + ", name: " +
> currItem.getName());
>     }
>   }
>
>   private void initItems() {
>     Collection items = new Vector();
>
>     items.add(new Item(new Long(1), "Item 1"));
>     items.add(new Item(new Long(2), "Item 2"));
>
>     setItems(items);
>   }
> }
>
>
>
>
>
>
>
> On 2/15/06, Ryan <cr...@gmail.com> wrote:
> >
> > You may want to look at the method prepareForRender(). This is the
> > method that handles binding of properties to form values. It is also
> > called just before the component is rendered and in the order in which
> > they are rendered on the page (where pageBeginRender is called before
> > anything renders and is called in an undefined order). Also note that
> > prepareForRender is not called if the component is not rendered (for
> > instance if it is in an @Conditional that evaluates to false).
> >
> > I have received the best results from using pageBeginRender for
> > initializing page properties that are static (ie known at all times
> > during render, for instance a property select model property) and
> > using prepareForRender in other times.
> >
> > Ryan
> >
> > On 2/14/06, Inge Solvoll <in...@gmail.com> wrote:
> > > I would like to provoke some debate on whether this is a good design
> > pattern
> > > or not:
> > >
> > > public void pageBeginRender(PageEvent event) {
> > >   initState();
> > >   readItemsFromDatabase();
> > > }
> > >
> > > private Collection readItemsFromDatabase() {
> > >   return getDatabaseConnection().getItems();
> > > }
> > >
> > > private void initState() {
> > >   // Init all crucial page state here
> > > }
> > >
> > > My problem is that some ids in hidden inputs are needed by the initState
> > > method. These values are not available in the pageBeginRender method
> > during
> > > rewind, because the Hidden components containing them haven't been
> > rendered
> > > yet. I need this state information on a per-request basis, not
> > per-session,
> > > so it is not possible to persist the page property. So far, I'm solving
> > this
> > > by using good-old request parameters, and reading them the old servlet
> > way
> > > in the pageBeginRender method like this:
> > >
> > > String crucialId = getRequest().getParameter("crucialId");
> > > page.setCrucialId(new Long(crucialId));
> > >
> > > I generally run into a lot of problems trying to find a good pattern for
> > > setting up data to fit with the RequestCycle. I have ended up doing the
> > > database reading in the pageBeginRender method, meaning that my data for
> > the
> > > page is being read on every single rewind and render. I find it a bit
> > hard
> > > to understand how to achieve this:
> > >
> > > On render:
> > > - Read data from database and set page properties
> > >
> > > On rewind:
> > > - Create non-null, empty, page properties ready to be populated from the
> > > request.
> > >
> > > My rewind step here often fails, and I don't see why. My page properties
> > > don't seem to be populated, when I leave them as, say, a non-null empty
> > > java.util.Collection to be populated with items from the request.
> > >
> > > Long and not very concentrated post, I actually don't know where to
> > start
> > > here :)
> > >
> > > Inge
> > >
> > >
> >
> > ---------------------------------------------------------------------
> > 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


Re: page state/cycle problem

Posted by Inge Solvoll <in...@gmail.com>.
I guess my (first) problem is simpler than this discussion, I'll try to
explain:

When I submit my form, I expect my page properties to be updated during
rewind automatically, without me having to write any java code to make that
happen. But so far I haven't understood how this happens. I include here a
simple code example that I think illustrates my problem quite well. Why is
my collection always empty when the form listener is reached? If I run the
initItems() method on both rewind and render, the values from the request
parameters are written into the page properties.

My ultimate question is: Do I really have to get the items list from the
database during rewind? Isn't there a way to avoid this, making tapestry
automatically build the items collection from the request parameters? As I
wrote in another similar post on the list about DataSqueezer, I've tried
creating a datasqueezer for this, but the collection is still showing up
empty.

My HTML file:

--------------------------------------------------------------------------

<body jwcid="@Body">

<form jwcid="@Form" listener="listener:formListener">

    <span jwcid="@For" source="ognl:items" value="ognl:currentItem">
      <span jwcid="@Insert" value="ognl:currentItem.name"/><br>
       <input type="text" jwcid="@TextField" value="ognl:currentItem.name"/>
       <br>
    </span>

<input type="button" jwcid="@Submit" value="Submit form now"/>

</form>
</body>

-------------------------------------------------------------

<page-specification class="Test">
    <property name="items"/>
    <property name="currentItem"/>
</page-specification>

-------------------------------------------------------------


public abstract class Test extends BasePage implements
PageBeginRenderListener {

  static Log log = LogFactory.getLog(Test.class);

  public abstract Collection getItems();
  public abstract void setItems(Collection c);

  public void pageBeginRender(PageEvent event) {

    if (!getRequestCycle().isRewinding()) {
      initItems();
    }
    else {
      if (getItems() == null) {
        setItems(new Vector());
      }
    }
  }

  public void formListener(IRequestCycle cycle) {
    Collection items = getItems();
    for (Iterator iter = items.iterator(); iter.hasNext();) {
      Item currItem = (Item) iter.next();
      log.debug("Current item id: " + currItem.getId() + ", name: " +
currItem.getName());
    }
  }

  private void initItems() {
    Collection items = new Vector();

    items.add(new Item(new Long(1), "Item 1"));
    items.add(new Item(new Long(2), "Item 2"));

    setItems(items);
  }
}







On 2/15/06, Ryan <cr...@gmail.com> wrote:
>
> You may want to look at the method prepareForRender(). This is the
> method that handles binding of properties to form values. It is also
> called just before the component is rendered and in the order in which
> they are rendered on the page (where pageBeginRender is called before
> anything renders and is called in an undefined order). Also note that
> prepareForRender is not called if the component is not rendered (for
> instance if it is in an @Conditional that evaluates to false).
>
> I have received the best results from using pageBeginRender for
> initializing page properties that are static (ie known at all times
> during render, for instance a property select model property) and
> using prepareForRender in other times.
>
> Ryan
>
> On 2/14/06, Inge Solvoll <in...@gmail.com> wrote:
> > I would like to provoke some debate on whether this is a good design
> pattern
> > or not:
> >
> > public void pageBeginRender(PageEvent event) {
> >   initState();
> >   readItemsFromDatabase();
> > }
> >
> > private Collection readItemsFromDatabase() {
> >   return getDatabaseConnection().getItems();
> > }
> >
> > private void initState() {
> >   // Init all crucial page state here
> > }
> >
> > My problem is that some ids in hidden inputs are needed by the initState
> > method. These values are not available in the pageBeginRender method
> during
> > rewind, because the Hidden components containing them haven't been
> rendered
> > yet. I need this state information on a per-request basis, not
> per-session,
> > so it is not possible to persist the page property. So far, I'm solving
> this
> > by using good-old request parameters, and reading them the old servlet
> way
> > in the pageBeginRender method like this:
> >
> > String crucialId = getRequest().getParameter("crucialId");
> > page.setCrucialId(new Long(crucialId));
> >
> > I generally run into a lot of problems trying to find a good pattern for
> > setting up data to fit with the RequestCycle. I have ended up doing the
> > database reading in the pageBeginRender method, meaning that my data for
> the
> > page is being read on every single rewind and render. I find it a bit
> hard
> > to understand how to achieve this:
> >
> > On render:
> > - Read data from database and set page properties
> >
> > On rewind:
> > - Create non-null, empty, page properties ready to be populated from the
> > request.
> >
> > My rewind step here often fails, and I don't see why. My page properties
> > don't seem to be populated, when I leave them as, say, a non-null empty
> > java.util.Collection to be populated with items from the request.
> >
> > Long and not very concentrated post, I actually don't know where to
> start
> > here :)
> >
> > Inge
> >
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>
>

Re: page state/cycle problem

Posted by Ryan <cr...@gmail.com>.
You may want to look at the method prepareForRender(). This is the
method that handles binding of properties to form values. It is also
called just before the component is rendered and in the order in which
they are rendered on the page (where pageBeginRender is called before
anything renders and is called in an undefined order). Also note that
prepareForRender is not called if the component is not rendered (for
instance if it is in an @Conditional that evaluates to false).

I have received the best results from using pageBeginRender for
initializing page properties that are static (ie known at all times
during render, for instance a property select model property) and
using prepareForRender in other times.

Ryan

On 2/14/06, Inge Solvoll <in...@gmail.com> wrote:
> I would like to provoke some debate on whether this is a good design pattern
> or not:
>
> public void pageBeginRender(PageEvent event) {
>   initState();
>   readItemsFromDatabase();
> }
>
> private Collection readItemsFromDatabase() {
>   return getDatabaseConnection().getItems();
> }
>
> private void initState() {
>   // Init all crucial page state here
> }
>
> My problem is that some ids in hidden inputs are needed by the initState
> method. These values are not available in the pageBeginRender method during
> rewind, because the Hidden components containing them haven't been rendered
> yet. I need this state information on a per-request basis, not per-session,
> so it is not possible to persist the page property. So far, I'm solving this
> by using good-old request parameters, and reading them the old servlet way
> in the pageBeginRender method like this:
>
> String crucialId = getRequest().getParameter("crucialId");
> page.setCrucialId(new Long(crucialId));
>
> I generally run into a lot of problems trying to find a good pattern for
> setting up data to fit with the RequestCycle. I have ended up doing the
> database reading in the pageBeginRender method, meaning that my data for the
> page is being read on every single rewind and render. I find it a bit hard
> to understand how to achieve this:
>
> On render:
> - Read data from database and set page properties
>
> On rewind:
> - Create non-null, empty, page properties ready to be populated from the
> request.
>
> My rewind step here often fails, and I don't see why. My page properties
> don't seem to be populated, when I leave them as, say, a non-null empty
> java.util.Collection to be populated with items from the request.
>
> Long and not very concentrated post, I actually don't know where to start
> here :)
>
> Inge
>
>

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


Re: page state/cycle problem

Posted by Shawn Church <sh...@boxity.com>.
Inge,

Re-reading your post, I think I may have misunderstood part of your 
question.  For situations like yours, I normally either let Tapestry 
persist the needed data (either request or session-scoped), or persist 
enough that I can reload everything in my form listener.  I do not think 
however that reloading data during the rewind phase is a very good idea, 
since any change in the data between render and rewind will of course 
cause problems.

One method I've used which works pretty well is to implement a transient 
boolean initialRender property which is set by the invoking page.  
Within pageBeginRender, if this flag is set I know it is safe to clear 
all session-persistent page properties (except those which are essential 
for an initial render).  This provides a simple but effective 
"page-visit persistence" scheme.

Shawn

Inge Solvoll wrote:
> I would like to provoke some debate on whether this is a good design pattern
> or not:
>
> public void pageBeginRender(PageEvent event) {
>   initState();
>   readItemsFromDatabase();
> }
>
> private Collection readItemsFromDatabase() {
>   return getDatabaseConnection().getItems();
> }
>
> private void initState() {
>   // Init all crucial page state here
> }
>
> My problem is that some ids in hidden inputs are needed by the initState
> method. These values are not available in the pageBeginRender method during
> rewind, because the Hidden components containing them haven't been rendered
> yet. I need this state information on a per-request basis, not per-session,
> so it is not possible to persist the page property. So far, I'm solving this
> by using good-old request parameters, and reading them the old servlet way
> in the pageBeginRender method like this:
>
> String crucialId = getRequest().getParameter("crucialId");
> page.setCrucialId(new Long(crucialId));
>
> I generally run into a lot of problems trying to find a good pattern for
> setting up data to fit with the RequestCycle. I have ended up doing the
> database reading in the pageBeginRender method, meaning that my data for the
> page is being read on every single rewind and render. I find it a bit hard
> to understand how to achieve this:
>
> On render:
> - Read data from database and set page properties
>
> On rewind:
> - Create non-null, empty, page properties ready to be populated from the
> request.
>
> My rewind step here often fails, and I don't see why. My page properties
> don't seem to be populated, when I leave them as, say, a non-null empty
> java.util.Collection to be populated with items from the request.
>
> Long and not very concentrated post, I actually don't know where to start
> here :)
>
> Inge
>
>   


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