You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by George Christman <gc...@cardaddy.com> on 2013/11/22 07:34:59 UTC

5.4 Bug with select nested inside form loop.

Hello, I have an ajaxformloop with a nested select menu loaded from the
database.

Lets say we have two rows in the list and both select menus have selected
values. When I remove the first row everything works as desired. If I
refresh the page I'm finding my now single row ajaxformloop select menu
sets the selected value to the now deleted rows selected value. Despite
page refreshes, the value remained. Now I found if I altered the id in the
select menu and then refreshed the page, the select menu now properly set
the selected value.

It seems as if the selected value is being cached, does anybody know what
might be going on?

Re: 5.4 Bug with select nested inside form loop.

Posted by Lance Java <la...@googlemail.com>.
Probably best to see some code before calling it a bug. Perhaps you are
initializing a variable in its  declaration (instead of @SetupRender) or
possibly a @Persist issue?

Re: 5.4 Bug with select nested inside form loop.

Posted by George Christman <gc...@cardaddy.com>.
Lance just incase your email client is stripping out the html.


On Mon, Nov 25, 2013 at 9:24 AM, George Christman
<gc...@cardaddy.com>wrote:

>
>
>
> On Sun, Nov 24, 2013 at 7:37 AM, Lance Java <la...@googlemail.com>wrote:
>
>> > I used very similar code in 5.3.7 without issue which is why I believe
>> this
>> is a bug.
>>
>> Ah, ok... I agree that this does point in the direction of a 5.4 bug.
>>
>>
>> > I was hoping to manage the formloop through the use of my person
>> object rather than having to manage the form loop through the phone object
>> and then having to sync the two objects up on the backend. Like I said, no
>> issues in 3.7.
>>
>> Can I see the related TML?
>>
>
> html t:type="layout" title="AjaxFormLoopDemo" xmlns:t="
> http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
> xmlns:p="tapestry:parameter">
>     t:form t:id="form">
>        div t:type="ajaxformloop" t:id="phones" source="person.phones"
> value="phone" encoder="encoder">
>             t:select t:id="type" model="selectModel"
> value="phone.phoneType"/>
>             t:textfield t:id="number" value="phone.number"/>
>             t:removerowlink>remove</t:removerowlink>
>         div>
>        input type="submit" value="Update"/>
>     /t:form>
> /html>
>
>
>>
>> > The reason for the tempid is do to the fact I get this exception when I
>> pass
>> a null id to the interface while trying to remove the row
>>
>> Ah, I see what you're doing... you can do this without tempId.
>> Option 1: Save the empty Phone you've created in onAddRow() to the
>> database
>> before returning so that it has an id and can be looked up later
>>
>
> In order to save the phone record, I would need to save the person record
> as well do to a not null constraint on person_id.
>
> Option 2: Your value encoder returns ***i-am-new*** in toClient() for a
>> phone who's id is null. It then returns new Phone() for ***i-am-new*** in
>> toValue()
>>
>
> I'm not sure I follow option 2, but sending a negative tempId to the
> frontend enables me to evaluate whether or not it will become a new object
> when the form is saved and toValue is called. toValue is called before
> setPhone, so if we return new Phone() in the encoder, the values of that
> field can be set from the frontend and eventually saved to the database
> with the person object. This approach prevents the user from saving
> unnecessary data to the database, prevents the need to use @Persist making
> it much more scalable, and handles the not blank value needed exception.
>
>
>> Option 3: @Persist your phones in the session. Your ValueEncoder then
>> converts between object and string using the array index
>>
>
> This is a possibility, however I don't believe this to be the most
> scalable approach do to the fact we are saving user data to the session.
>
> If you have sometime, you should try creating a new quickstart project
> using 5.4 and just just copy the code / classes I provided. It will give
> you a chance to see how this approach works, but more importantly
> demonstrate the bug.
>
> I've been able to determine this is a FireFox issue using 25.0.1. on both
> my pc and mac, so I'm not sure if that gets us any closer.
>
> Thanks Lance.
>
>
>> On 23 November 2013 23:06, George Christman <gc...@cardaddy.com>
>> wrote:
>>
>> > On Sat, Nov 23, 2013 at 4:48 AM, Lance Java <lance.java@googlemail.com
>> > >wrote:
>> >
>> > > I'm still not convinced this is a bug in tapestry... it might be but
>> > > there's still some suspect areas in your code.
>> > >
>> >
>> > I used very similar code in 5.3.7 without issue which is why I believe
>> this
>> > is a bug. I was hoping to manage the formloop through the use of my
>> person
>> > object rather than having to manage the form loop through the phone
>> object
>> > and then having to sync the two objects up on the backend. Like I said,
>> no
>> > issues in 3.7.
>> >
>> >
>> > >
>> > > 1. In hibernate, Phone has-a Person (@ManyToOne) and Person has
>> Phones(s)
>> > > (@OneToMany) but you seem to be manipulating both:
>> > >
>> > >     @CommitAfter
>> > >     void onRemoveRow(Phone phone) {
>> > >         person.getPhones().remove(phone);
>> > >         session.delete(phone);
>> > >     }
>> > >
>> > > I'm thinking you should manipulate one and get the other from
>> hibernate.
>> > >
>> >
>> > Your correct, I do not need the person.getPhones().remove(phone); Not
>> sure
>> > why I was thinking I needed it.  I now just delete the phone object, but
>> > still no change.
>> >
>> > In my real project the fields are already added from the database so I
>> was
>> > able to test the component by removing the encoder from the
>> ajaxformloop.
>> > When I delete, still same issue. Even if I refresh the page after
>> deletion,
>> > still holds onto the wrong values.  I'd like to point out i'm using
>> firefox
>> > too.
>> >
>> > >
>> > > 2. This whole @Transient temp id -System.nanoTime() thingy. Why is
>> this
>> > > required?
>> > > It looks like you've let your UI implementation creep into your model.
>> > > Always a bad idea ;)
>> > >
>> >
>> > The reason for the tempid is do to the fact I get this exception when I
>> > pass a null id to the interface while trying to remove the row
>> >
>> > *The value for query parameter 't:rowvalue' was blank, but a non-blank
>> > value is needed.*
>> >
>> > >
>> > > 3. PhoneTypes doesn't relate to Person... these look like globals.
>> > > I'd really advise against initializing them in your page.
>> > > Looks more like a @Startup job or at least a synchronized method on a
>> > > service.
>> > >
>> > > This isn't production code, I just through some demo code together to
>> > illistrate the issue. I wrote the code enabling you guys to quickly be
>> able
>> > to test the component and determine if what I found was a bug.
>> >
>> > I still believe it has something to do with how the form loop holds on
>> to
>> > values. I notice serverside validation now works properly, so I wonder
>> if
>> > the issue has something to do with that bug fix.
>> >
>> > >
>> > >
>> > > On 22 November 2013 20:50, George Christman <gc...@cardaddy.com>
>> > > wrote:
>> > >
>> > > > Your on :) you can just paypal me haha.
>> > > >
>> > > > Well the value encoder doesn't appear to be the issue. :( I can
>> > > completely
>> > > > remove the encoder parameter from the component and refresh the page
>> > and
>> > > it
>> > > > will still hold on to the wrong result despite the correct select
>> > option
>> > > > being selected in the select menu. I tried clearing my browser
>> cache as
>> > > > well, no change. Should I file a bug report with JIRA?
>> > > >
>> > > >
>> > > > On Fri, Nov 22, 2013 at 3:24 PM, Lance Java <
>> lance.java@googlemail.com
>> > > > >wrote:
>> > > >
>> > > > > As I said... I haven't taken the time to fully understand the
>> code.
>> > > > >
>> > > > > That being said, I'd be willing to bet you a fiver that it's
>> causing
>> > > the
>> > > > > issue
>> > > > > :)
>> > > > >
>> > > >
>> > > >
>> > > >
>> > > > --
>> > > > George Christman
>> > > > www.CarDaddy.com
>> > > > P.O. Box 735
>> > > > Johnstown, New York
>> > > >
>> > >
>> >
>> >
>> >
>> > --
>> > George Christman
>> > www.CarDaddy.com
>> > P.O. Box 735
>> > Johnstown, New York
>> >
>>
>
>
>
> --
> George Christman
> www.CarDaddy.com
> P.O. Box 735
> Johnstown, New York
>
>


-- 
George Christman
www.CarDaddy.com
P.O. Box 735
Johnstown, New York

Re: 5.4 Bug with select nested inside form loop.

Posted by George Christman <gc...@cardaddy.com>.
On Sun, Nov 24, 2013 at 7:37 AM, Lance Java <la...@googlemail.com>wrote:

> > I used very similar code in 5.3.7 without issue which is why I believe
> this
> is a bug.
>
> Ah, ok... I agree that this does point in the direction of a 5.4 bug.
>
>
> > I was hoping to manage the formloop through the use of my person
> object rather than having to manage the form loop through the phone object
> and then having to sync the two objects up on the backend. Like I said, no
> issues in 3.7.
>
> Can I see the related TML?
>

<html t:type="layout" title="AjaxFormLoopDemo" xmlns:t="
http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
xmlns:p="tapestry:parameter">
    <t:form t:id="form">
        <div t:type="ajaxformloop" t:id="phones" source="person.phones"
value="phone" encoder="encoder">
            <t:select t:id="type" model="selectModel"
value="phone.phoneType"/>
            <t:textfield t:id="number" value="phone.number"/>
            <t:removerowlink>remove</t:removerowlink>
        </div>
        <input type="submit" value="Update"/>
    </t:form>
</html>


>
> > The reason for the tempid is do to the fact I get this exception when I
> pass
> a null id to the interface while trying to remove the row
>
> Ah, I see what you're doing... you can do this without tempId.
> Option 1: Save the empty Phone you've created in onAddRow() to the database
> before returning so that it has an id and can be looked up later
>

In order to save the phone record, I would need to save the person record
as well do to a not null constraint on person_id.

Option 2: Your value encoder returns ***i-am-new*** in toClient() for a
> phone who's id is null. It then returns new Phone() for ***i-am-new*** in
> toValue()
>

I'm not sure I follow option 2, but sending a negative tempId to the
frontend enables me to evaluate whether or not it will become a new object
when the form is saved and toValue is called. toValue is called before
setPhone, so if we return new Phone() in the encoder, the values of that
field can be set from the frontend and eventually saved to the database
with the person object. This approach prevents the user from saving
unnecessary data to the database, prevents the need to use @Persist making
it much more scalable, and handles the not blank value needed exception.


> Option 3: @Persist your phones in the session. Your ValueEncoder then
> converts between object and string using the array index
>

This is a possibility, however I don't believe this to be the most scalable
approach do to the fact we are saving user data to the session.

If you have sometime, you should try creating a new quickstart project
using 5.4 and just just copy the code / classes I provided. It will give
you a chance to see how this approach works, but more importantly
demonstrate the bug.

I've been able to determine this is a FireFox issue using 25.0.1. on both
my pc and mac, so I'm not sure if that gets us any closer.

Thanks Lance.


> On 23 November 2013 23:06, George Christman <gc...@cardaddy.com>
> wrote:
>
> > On Sat, Nov 23, 2013 at 4:48 AM, Lance Java <lance.java@googlemail.com
> > >wrote:
> >
> > > I'm still not convinced this is a bug in tapestry... it might be but
> > > there's still some suspect areas in your code.
> > >
> >
> > I used very similar code in 5.3.7 without issue which is why I believe
> this
> > is a bug. I was hoping to manage the formloop through the use of my
> person
> > object rather than having to manage the form loop through the phone
> object
> > and then having to sync the two objects up on the backend. Like I said,
> no
> > issues in 3.7.
> >
> >
> > >
> > > 1. In hibernate, Phone has-a Person (@ManyToOne) and Person has
> Phones(s)
> > > (@OneToMany) but you seem to be manipulating both:
> > >
> > >     @CommitAfter
> > >     void onRemoveRow(Phone phone) {
> > >         person.getPhones().remove(phone);
> > >         session.delete(phone);
> > >     }
> > >
> > > I'm thinking you should manipulate one and get the other from
> hibernate.
> > >
> >
> > Your correct, I do not need the person.getPhones().remove(phone); Not
> sure
> > why I was thinking I needed it.  I now just delete the phone object, but
> > still no change.
> >
> > In my real project the fields are already added from the database so I
> was
> > able to test the component by removing the encoder from the ajaxformloop.
> > When I delete, still same issue. Even if I refresh the page after
> deletion,
> > still holds onto the wrong values.  I'd like to point out i'm using
> firefox
> > too.
> >
> > >
> > > 2. This whole @Transient temp id -System.nanoTime() thingy. Why is this
> > > required?
> > > It looks like you've let your UI implementation creep into your model.
> > > Always a bad idea ;)
> > >
> >
> > The reason for the tempid is do to the fact I get this exception when I
> > pass a null id to the interface while trying to remove the row
> >
> > *The value for query parameter 't:rowvalue' was blank, but a non-blank
> > value is needed.*
> >
> > >
> > > 3. PhoneTypes doesn't relate to Person... these look like globals.
> > > I'd really advise against initializing them in your page.
> > > Looks more like a @Startup job or at least a synchronized method on a
> > > service.
> > >
> > > This isn't production code, I just through some demo code together to
> > illistrate the issue. I wrote the code enabling you guys to quickly be
> able
> > to test the component and determine if what I found was a bug.
> >
> > I still believe it has something to do with how the form loop holds on to
> > values. I notice serverside validation now works properly, so I wonder if
> > the issue has something to do with that bug fix.
> >
> > >
> > >
> > > On 22 November 2013 20:50, George Christman <gc...@cardaddy.com>
> > > wrote:
> > >
> > > > Your on :) you can just paypal me haha.
> > > >
> > > > Well the value encoder doesn't appear to be the issue. :( I can
> > > completely
> > > > remove the encoder parameter from the component and refresh the page
> > and
> > > it
> > > > will still hold on to the wrong result despite the correct select
> > option
> > > > being selected in the select menu. I tried clearing my browser cache
> as
> > > > well, no change. Should I file a bug report with JIRA?
> > > >
> > > >
> > > > On Fri, Nov 22, 2013 at 3:24 PM, Lance Java <
> lance.java@googlemail.com
> > > > >wrote:
> > > >
> > > > > As I said... I haven't taken the time to fully understand the code.
> > > > >
> > > > > That being said, I'd be willing to bet you a fiver that it's
> causing
> > > the
> > > > > issue
> > > > > :)
> > > > >
> > > >
> > > >
> > > >
> > > > --
> > > > George Christman
> > > > www.CarDaddy.com
> > > > P.O. Box 735
> > > > Johnstown, New York
> > > >
> > >
> >
> >
> >
> > --
> > George Christman
> > www.CarDaddy.com
> > P.O. Box 735
> > Johnstown, New York
> >
>



-- 
George Christman
www.CarDaddy.com
P.O. Box 735
Johnstown, New York

Re: 5.4 Bug with select nested inside form loop.

Posted by Lance Java <la...@googlemail.com>.
> I used very similar code in 5.3.7 without issue which is why I believe
this
is a bug.

Ah, ok... I agree that this does point in the direction of a 5.4 bug.


> I was hoping to manage the formloop through the use of my person
object rather than having to manage the form loop through the phone object
and then having to sync the two objects up on the backend. Like I said, no
issues in 3.7.

Can I see the related TML?

> The reason for the tempid is do to the fact I get this exception when I pass
a null id to the interface while trying to remove the row

Ah, I see what you're doing... you can do this without tempId.
Option 1: Save the empty Phone you've created in onAddRow() to the database
before returning so that it has an id and can be looked up later
Option 2: Your value encoder returns ***i-am-new*** in toClient() for a
phone who's id is null. It then returns new Phone() for ***i-am-new*** in
toValue()
Option 3: @Persist your phones in the session. Your ValueEncoder then
converts between object and string using the array index



On 23 November 2013 23:06, George Christman <gc...@cardaddy.com> wrote:

> On Sat, Nov 23, 2013 at 4:48 AM, Lance Java <lance.java@googlemail.com
> >wrote:
>
> > I'm still not convinced this is a bug in tapestry... it might be but
> > there's still some suspect areas in your code.
> >
>
> I used very similar code in 5.3.7 without issue which is why I believe this
> is a bug. I was hoping to manage the formloop through the use of my person
> object rather than having to manage the form loop through the phone object
> and then having to sync the two objects up on the backend. Like I said, no
> issues in 3.7.
>
>
> >
> > 1. In hibernate, Phone has-a Person (@ManyToOne) and Person has Phones(s)
> > (@OneToMany) but you seem to be manipulating both:
> >
> >     @CommitAfter
> >     void onRemoveRow(Phone phone) {
> >         person.getPhones().remove(phone);
> >         session.delete(phone);
> >     }
> >
> > I'm thinking you should manipulate one and get the other from hibernate.
> >
>
> Your correct, I do not need the person.getPhones().remove(phone); Not sure
> why I was thinking I needed it.  I now just delete the phone object, but
> still no change.
>
> In my real project the fields are already added from the database so I was
> able to test the component by removing the encoder from the ajaxformloop.
> When I delete, still same issue. Even if I refresh the page after deletion,
> still holds onto the wrong values.  I'd like to point out i'm using firefox
> too.
>
> >
> > 2. This whole @Transient temp id -System.nanoTime() thingy. Why is this
> > required?
> > It looks like you've let your UI implementation creep into your model.
> > Always a bad idea ;)
> >
>
> The reason for the tempid is do to the fact I get this exception when I
> pass a null id to the interface while trying to remove the row
>
> *The value for query parameter 't:rowvalue' was blank, but a non-blank
> value is needed.*
>
> >
> > 3. PhoneTypes doesn't relate to Person... these look like globals.
> > I'd really advise against initializing them in your page.
> > Looks more like a @Startup job or at least a synchronized method on a
> > service.
> >
> > This isn't production code, I just through some demo code together to
> illistrate the issue. I wrote the code enabling you guys to quickly be able
> to test the component and determine if what I found was a bug.
>
> I still believe it has something to do with how the form loop holds on to
> values. I notice serverside validation now works properly, so I wonder if
> the issue has something to do with that bug fix.
>
> >
> >
> > On 22 November 2013 20:50, George Christman <gc...@cardaddy.com>
> > wrote:
> >
> > > Your on :) you can just paypal me haha.
> > >
> > > Well the value encoder doesn't appear to be the issue. :( I can
> > completely
> > > remove the encoder parameter from the component and refresh the page
> and
> > it
> > > will still hold on to the wrong result despite the correct select
> option
> > > being selected in the select menu. I tried clearing my browser cache as
> > > well, no change. Should I file a bug report with JIRA?
> > >
> > >
> > > On Fri, Nov 22, 2013 at 3:24 PM, Lance Java <lance.java@googlemail.com
> > > >wrote:
> > >
> > > > As I said... I haven't taken the time to fully understand the code.
> > > >
> > > > That being said, I'd be willing to bet you a fiver that it's causing
> > the
> > > > issue
> > > > :)
> > > >
> > >
> > >
> > >
> > > --
> > > George Christman
> > > www.CarDaddy.com
> > > P.O. Box 735
> > > Johnstown, New York
> > >
> >
>
>
>
> --
> George Christman
> www.CarDaddy.com
> P.O. Box 735
> Johnstown, New York
>

Re: 5.4 Bug with select nested inside form loop.

Posted by George Christman <gc...@cardaddy.com>.
On Sat, Nov 23, 2013 at 4:48 AM, Lance Java <la...@googlemail.com>wrote:

> I'm still not convinced this is a bug in tapestry... it might be but
> there's still some suspect areas in your code.
>

I used very similar code in 5.3.7 without issue which is why I believe this
is a bug. I was hoping to manage the formloop through the use of my person
object rather than having to manage the form loop through the phone object
and then having to sync the two objects up on the backend. Like I said, no
issues in 3.7.


>
> 1. In hibernate, Phone has-a Person (@ManyToOne) and Person has Phones(s)
> (@OneToMany) but you seem to be manipulating both:
>
>     @CommitAfter
>     void onRemoveRow(Phone phone) {
>         person.getPhones().remove(phone);
>         session.delete(phone);
>     }
>
> I'm thinking you should manipulate one and get the other from hibernate.
>

Your correct, I do not need the person.getPhones().remove(phone); Not sure
why I was thinking I needed it.  I now just delete the phone object, but
still no change.

In my real project the fields are already added from the database so I was
able to test the component by removing the encoder from the ajaxformloop.
When I delete, still same issue. Even if I refresh the page after deletion,
still holds onto the wrong values.  I'd like to point out i'm using firefox
too.

>
> 2. This whole @Transient temp id -System.nanoTime() thingy. Why is this
> required?
> It looks like you've let your UI implementation creep into your model.
> Always a bad idea ;)
>

The reason for the tempid is do to the fact I get this exception when I
pass a null id to the interface while trying to remove the row

*The value for query parameter 't:rowvalue' was blank, but a non-blank
value is needed.*

>
> 3. PhoneTypes doesn't relate to Person... these look like globals.
> I'd really advise against initializing them in your page.
> Looks more like a @Startup job or at least a synchronized method on a
> service.
>
> This isn't production code, I just through some demo code together to
illistrate the issue. I wrote the code enabling you guys to quickly be able
to test the component and determine if what I found was a bug.

I still believe it has something to do with how the form loop holds on to
values. I notice serverside validation now works properly, so I wonder if
the issue has something to do with that bug fix.

>
>
> On 22 November 2013 20:50, George Christman <gc...@cardaddy.com>
> wrote:
>
> > Your on :) you can just paypal me haha.
> >
> > Well the value encoder doesn't appear to be the issue. :( I can
> completely
> > remove the encoder parameter from the component and refresh the page and
> it
> > will still hold on to the wrong result despite the correct select option
> > being selected in the select menu. I tried clearing my browser cache as
> > well, no change. Should I file a bug report with JIRA?
> >
> >
> > On Fri, Nov 22, 2013 at 3:24 PM, Lance Java <lance.java@googlemail.com
> > >wrote:
> >
> > > As I said... I haven't taken the time to fully understand the code.
> > >
> > > That being said, I'd be willing to bet you a fiver that it's causing
> the
> > > issue
> > > :)
> > >
> >
> >
> >
> > --
> > George Christman
> > www.CarDaddy.com
> > P.O. Box 735
> > Johnstown, New York
> >
>



-- 
George Christman
www.CarDaddy.com
P.O. Box 735
Johnstown, New York

Re: 5.4 Bug with select nested inside form loop.

Posted by Lance Java <la...@googlemail.com>.
I'm still not convinced this is a bug in tapestry... it might be but
there's still some suspect areas in your code.

1. In hibernate, Phone has-a Person (@ManyToOne) and Person has Phones(s)
(@OneToMany) but you seem to be manipulating both:

    @CommitAfter
    void onRemoveRow(Phone phone) {
        person.getPhones().remove(phone);
        session.delete(phone);
    }

I'm thinking you should manipulate one and get the other from hibernate.

2. This whole @Transient temp id -System.nanoTime() thingy. Why is this
required?
It looks like you've let your UI implementation creep into your model.
Always a bad idea ;)

3. PhoneTypes doesn't relate to Person... these look like globals.
I'd really advise against initializing them in your page.
Looks more like a @Startup job or at least a synchronized method on a
service.



On 22 November 2013 20:50, George Christman <gc...@cardaddy.com> wrote:

> Your on :) you can just paypal me haha.
>
> Well the value encoder doesn't appear to be the issue. :( I can completely
> remove the encoder parameter from the component and refresh the page and it
> will still hold on to the wrong result despite the correct select option
> being selected in the select menu. I tried clearing my browser cache as
> well, no change. Should I file a bug report with JIRA?
>
>
> On Fri, Nov 22, 2013 at 3:24 PM, Lance Java <lance.java@googlemail.com
> >wrote:
>
> > As I said... I haven't taken the time to fully understand the code.
> >
> > That being said, I'd be willing to bet you a fiver that it's causing the
> > issue
> > :)
> >
>
>
>
> --
> George Christman
> www.CarDaddy.com
> P.O. Box 735
> Johnstown, New York
>

Re: 5.4 Bug with select nested inside form loop.

Posted by George Christman <gc...@cardaddy.com>.
Your on :) you can just paypal me haha.

Well the value encoder doesn't appear to be the issue. :( I can completely
remove the encoder parameter from the component and refresh the page and it
will still hold on to the wrong result despite the correct select option
being selected in the select menu. I tried clearing my browser cache as
well, no change. Should I file a bug report with JIRA?


On Fri, Nov 22, 2013 at 3:24 PM, Lance Java <la...@googlemail.com>wrote:

> As I said... I haven't taken the time to fully understand the code.
>
> That being said, I'd be willing to bet you a fiver that it's causing the
> issue
> :)
>



-- 
George Christman
www.CarDaddy.com
P.O. Box 735
Johnstown, New York

Re: 5.4 Bug with select nested inside form loop.

Posted by Lance Java <la...@googlemail.com>.
As I said... I haven't taken the time to fully understand the code.

That being said, I'd be willing to bet you a fiver that it's causing the
issue
:)

Re: 5.4 Bug with select nested inside form loop.

Posted by George Christman <gc...@cardaddy.com>.
Yes I'm aware and I'm also aware the encoder is fired twice while adding a
row, once for the row and a second time for the remove action. The
ajaxformloop has never seemed to be straight forward, I'm always interested
in a simpler approach. Do you believe this may be the cause of the issue?


On Fri, Nov 22, 2013 at 3:02 PM, Lance Java <la...@googlemail.com>wrote:

> I'm assuming you know that the encoder is fired every time a conversion
> between clientside id and serverside object is done. This includes your
> delete action etc.
>



-- 
George Christman
www.CarDaddy.com
P.O. Box 735
Johnstown, New York

Re: 5.4 Bug with select nested inside form loop.

Posted by Lance Java <la...@googlemail.com>.
I'm assuming you know that the encoder is fired every time a conversion
between clientside id and serverside object is done. This includes your
delete action etc.

Re: 5.4 Bug with select nested inside form loop.

Posted by Lance Java <la...@googlemail.com>.
I didn't take the time to fully understand your code but a ValueEncoder's
role is solely to serialize between clientside string and serverside
object. Nothing more.

Re: 5.4 Bug with select nested inside form loop.

Posted by George Christman <gc...@cardaddy.com>.
Without that line the phone object never gets added to the person object
prior to commit. Do you know of a better approach?


On Fri, Nov 22, 2013 at 2:20 PM, Lance Java <la...@googlemail.com>wrote:

> Why is your encoder calling
> person.getPhones().add(phone)???
>
> That looks totally dodgy!
>



-- 
George Christman
www.CarDaddy.com
P.O. Box 735
Johnstown, New York

Re: 5.4 Bug with select nested inside form loop.

Posted by Lance Java <la...@googlemail.com>.
Why is your encoder calling
person.getPhones().add(phone)???

That looks totally dodgy!

Re: 5.4 Bug with select nested inside form loop.

Posted by George Christman <gc...@cardaddy.com>.
I would like to share some additional details related to this issue. I'm
finding after removing a row and refreshing the page the selected option is
marked selected in the html correctly, however the option displayed in the
select menu is the former select option from the previously deleted row.
I'm not sure why the selected option is being ignored. If I change the
ajaxformloop to a loop and refresh the page, all my select options the
appear to be correct. Below is the code used to reproduce the bug.

How I to reproduce it.

Add 3 rows.

Row 1. Select Mobile - Type "test1"
Row 2. Select Home - Type "test2"
Row 3 Select Fax - Type "test3"

Save results

Remove Row 1

Refresh page.

Notice how the results change to the following.

Row 1. Select Mobile - Type "test2"
Row 2. Select Home - Type "test3"

Code used to reproduce bug.

tml

<html t:type="layout" title="AjaxFormLoopDemo" xmlns:t="
http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
xmlns:p="tapestry:parameter">
    <t:form t:id="form">
        <div t:type="ajaxformloop" t:id="phones" source="person.phones"
value="phone" encoder="encoder">
            <t:select t:id="type" model="selectModel"
value="phone.phoneType"/>
            <t:textfield t:id="number" value="phone.number"/>
            <t:removerowlink>remove</t:removerowlink>
        </div>
        <input type="submit" value="Update"/>
    </t:form>
</html>

java

public class AjaxFormLoopDemo {

    @Property
    private Phone phone;
    @PageActivationContext
    @Property
    private Person person;
    @Inject
    private SelectModelFactory selectModelFactory;
    @Inject
    private Session session;

    void onPrepare() {
        if (person == null) {
            person = new Person();
        }

        List<PhoneType> phoneTypes =
session.createCriteria(PhoneType.class).addOrder(Order.desc("id")).list();

        if (phoneTypes.isEmpty()) {
            setupPhoneTypes();
        }
    }

    @CommitAfter
    public void setupPhoneTypes() {
        PhoneType phoneType = new PhoneType("HOME");
        session.save(phoneType);

        phoneType = new PhoneType("MOBILE");
        session.save(phoneType);

        phoneType = new PhoneType("FAX");
        session.save(phoneType);
    }

    @CommitAfter
    public void onSuccess() {
        session.saveOrUpdate(person);
    }

    public SelectModel getSelectModel() {
        List<PhoneType> phoneTypes =
session.createCriteria(PhoneType.class).addOrder(Order.asc("type")).list();
        return selectModelFactory.create(phoneTypes, "type");
    }

    Object onAddRow() {
        return new Phone(person);
    }

    @CommitAfter
    void onRemoveRow(Phone phone) {
        person.getPhones().remove(phone);
        session.delete(phone);
    }

    public ValueEncoder<Phone> getEncoder() {
        return new ValueEncoder<Phone>() {
            @Override
            public String toClient(Phone v) {
                Long id = v.getId();
                return id != null ? id.toString() :
v.getTempId().toString();
            }

            @Override
            public Phone toValue(String toValue) {
                Long id = Long.parseLong(toValue);

                if (id > 0) {
                    Phone phone = (Phone) session.get(Phone.class, id);
                    return phone;
                }
                Phone phone = new Phone(person);
                person.getPhones().add(phone);
                return phone;
            }
        };
    }
}

Person entity

@Entity
public class Person implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "person", cascade = CascadeType.ALL,
orphanRemoval = true)
    @OrderBy("id")
    private List<Phone> phones;

    @Transient
    private Long tempId = -System.nanoTime();

    public Person() {
    }

    public Long getTempId() {
        return tempId;
    }

    public void setTempId(Long tempId) {
        this.tempId = tempId;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public List<Phone> getPhones() {
        if (phones == null) {
            phones = new ArrayList<>();
        }
        return phones;
    }

    public void setPhones(List<Phone> phones) {
        this.phones = phones;
    }

}

Phone Entity

@Entity
public class Phone implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @ManyToOne
    @JoinColumn(name = "phone_type_id")
    private PhoneType phoneType;
    @ManyToOne
    @JoinColumn(name = "person_id")
    private Person person;
    private String number;
    @Transient
    private Long tempId = -System.nanoTime();

    public Phone() {
    }

    public Phone(Person person) {
        this.person = person;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public Long getTempId() {
        return tempId;
    }

    public void setTempId(Long tempId) {
        this.tempId = tempId;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public PhoneType getPhoneType() {
        return phoneType;
    }

    public void setPhoneType(PhoneType phoneType) {
        this.phoneType = phoneType;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

}

PhoneType entity

@Entity
public class PhoneType implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String type;
    @Transient
    private Long tempId = -System.nanoTime();

    public PhoneType() {
    }

    public PhoneType(String type) {
        this.type = type;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Long getTempId() {
        return tempId;
    }

    public void setTempId(Long tempId) {
        this.tempId = tempId;
    }

}


On Fri, Nov 22, 2013 at 1:34 AM, George Christman
<gc...@cardaddy.com>wrote:

> Hello, I have an ajaxformloop with a nested select menu loaded from the
> database.
>
> Lets say we have two rows in the list and both select menus have selected
> values. When I remove the first row everything works as desired. If I
> refresh the page I'm finding my now single row ajaxformloop select menu
> sets the selected value to the now deleted rows selected value. Despite
> page refreshes, the value remained. Now I found if I altered the id in the
> select menu and then refreshed the page, the select menu now properly set
> the selected value.
>
> It seems as if the selected value is being cached, does anybody know what
> might be going on?
>
>


-- 
George Christman
www.CarDaddy.com
P.O. Box 735
Johnstown, New York