You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Marek Zachara <ma...@telperion.pl> on 2006/12/23 21:23:04 UTC

Action not called when the value for rendered attribute changes

Hello,

I have a scenario which seems to be trival, so i guess i must have missed 
something obvious, but still i cant seem to find a solution

on a page i have a sample form with a command button connected to the backing 
beans:
<h:commandButton value="Test Me" action="#{bean1.testAction}" 
rendered="#{bean2.showMe}" />

both bean1 and bean2 have scope=request

now, bean2 is created during the generation of the page, 
and method isShowMe() returns true;

the button is displayed. i can click it, though to my surprise
the action is not called (i have put a log message in testAction to verify 
that). Even the bean1 itself is not created.

as i have found out, this is due to the rendered attribute - when 
i set it to true or bind it to a some method in session bean, everything 
works fine. The bean2 is destroyed after generation of the page with the 
button, so it seems as it is trying to access it nevertheless after
the button is clicked, fails and as a result the whole action fails.
I have tried it also with attribute immediate="true" , but with no 
success either.

i will really be glad if anyone can help me out :)

Marek

Re: Action not called when the value for rendered attribute changes

Posted by Marek Zachara <ma...@telperion.pl>.
Yes, thanks t:saveState does do the trick, though its an overkill
to use tomahawk just for that purpose :)

anyway, if this is 'by design' behaviour then i'll have to live
with it and i have already done some work-arounds, 
but i'm not really convinced it should work this way. I mean
myfaces shall not need the rendered property value AFTER it has
been rendered.

Marek

On Saturday 23 December 2006 22:42, Mike Kienenberger wrote:
> Request scope is too short.
>
> The scope of the rendered attribute value must remain constant from
> renderResponse of the first request to processing the action on the
> second request.
>
> Use t:saveState on either bean2 or on bean2.showMe.
>
> On 12/23/06, Marek Zachara <ma...@telperion.pl> wrote:
> > Hello,
> >
> > I have a scenario which seems to be trival, so i guess i must have missed
> > something obvious, but still i cant seem to find a solution
> >
> > on a page i have a sample form with a command button connected to the
> > backing beans:
> > <h:commandButton value="Test Me" action="#{bean1.testAction}"
> > rendered="#{bean2.showMe}" />
> >
> > both bean1 and bean2 have scope=request
> >
> > now, bean2 is created during the generation of the page,
> > and method isShowMe() returns true;
> >
> > the button is displayed. i can click it, though to my surprise
> > the action is not called (i have put a log message in testAction to
> > verify that). Even the bean1 itself is not created.
> >
> > as i have found out, this is due to the rendered attribute - when
> > i set it to true or bind it to a some method in session bean, everything
> > works fine. The bean2 is destroyed after generation of the page with the
> > button, so it seems as it is trying to access it nevertheless after
> > the button is clicked, fails and as a result the whole action fails.
> > I have tried it also with attribute immediate="true" , but with no
> > success either.
> >
> > i will really be glad if anyone can help me out :)
> >
> > Marek

Re: Action not called when the value for rendered attribute changes

Posted by Mike Kienenberger <mk...@gmail.com>.
Request scope is too short.

The scope of the rendered attribute value must remain constant from
renderResponse of the first request to processing the action on the
second request.

Use t:saveState on either bean2 or on bean2.showMe.


On 12/23/06, Marek Zachara <ma...@telperion.pl> wrote:
> Hello,
>
> I have a scenario which seems to be trival, so i guess i must have missed
> something obvious, but still i cant seem to find a solution
>
> on a page i have a sample form with a command button connected to the backing
> beans:
> <h:commandButton value="Test Me" action="#{bean1.testAction}"
> rendered="#{bean2.showMe}" />
>
> both bean1 and bean2 have scope=request
>
> now, bean2 is created during the generation of the page,
> and method isShowMe() returns true;
>
> the button is displayed. i can click it, though to my surprise
> the action is not called (i have put a log message in testAction to verify
> that). Even the bean1 itself is not created.
>
> as i have found out, this is due to the rendered attribute - when
> i set it to true or bind it to a some method in session bean, everything
> works fine. The bean2 is destroyed after generation of the page with the
> button, so it seems as it is trying to access it nevertheless after
> the button is clicked, fails and as a result the whole action fails.
> I have tried it also with attribute immediate="true" , but with no
> success either.
>
> i will really be glad if anyone can help me out :)
>
> Marek
>

Re: Action not called when the value for rendered attribute changes

Posted by Mike Kienenberger <mk...@gmail.com>.
Marek, you could submit a wishlist item on this, but it's a issue with
the design of JSF and not something that can be fixed in MyFaces.

The real issue is that you need page-scoped data often times in JSF,
and that scope is not supported by default.

t:saveState (and the equivalents in ADFFaces and other component
libraries) is one approach to solve the problem.   It allows you to
have complete control over the scope of the target.

I think that Craig's Shale project also provides some page-scoping
functionality by declaring one specific bean to be a page-scoped
backing bean for a view, although I have never used it.

On 12/24/06, Marek Zachara <ma...@telperion.pl> wrote:
> On Sunday 24 December 2006 00:11, Craig McClanahan wrote:
> > On 12/23/06, Marek Zachara <ma...@telperion.pl> wrote:
> > > certainly, though it boils down to extremely simple scenario:
> > >
> > > bean1 (scope="request"):
> > > public String testAction() {
> > >         System.out.print("Test Action");
> > >         return null;
> > > }
> > >
> > > bean2 (scope="request"):
> > > private boolean show = false;
> > > public setShow() {
> > >         this.showMe = true;
> > > }
> > > public boolean showMe() {
> > >         return this.showMe;
> > > }
> > >
> > > jsf page:
> > > ....
> > > some code that calls bean2.setShow
> > > ....
> > > <h:commandButton value="Test Me" action="#{bean1.testAction}"
> > > rendered="#{bean2.showMe}" />
> > >
> > >
> > > the above is enough to reporoduce the behaviour (nothing will
> > > be written in the log/stdout
> >
> > Actually, this behavior is "by design" and you need to adapt your
> > application logic to it.
> >
> > The "rendered" property is used in *two* places  for command and input
> > components (including <h:commandButton> here):
> >
> > * During Render Response, to determine whether or not to render
> >   the component at all.
> >
> > * During Apply Request Values on the subsequent postback, to
> >   determine whether or not the input value should be decoded
> >   and processed.  (The "disabled" property, when present, is also
> >   a part of this test but isn't relevant for your example use case.)
> >
> > It's the second one that is biting you with your current logic -- as the
> > component tree is getting reconstructed during Restore View, the "#{
> > bean2.showMe}" expression is evaluated (creating a new instance of Bean2)
> > ... and that returns your default value of "false".
> >
> > To do what you are trying to do, you need to have the calculated value for
> > the "showMe" property survive from one request to the next.  A few ways to
> > make that happen:
> >
> > * As suggested, use <t:saveState> (although I'm on record
> >   as not liking this, because it mixes business logic and presentation
> >   logic in the page :-).
> >
> > * Put bean2 in session scope instead of request scope.  That
> >   way, the previously set value will be remembered.
> >
> this solution does not seem practical in my case as i have quite a few
> beans that would have to be put into session scope - and i certainly
> dont want to have them 'hanging around' all the time. So i have
> gathered all this rendering attributes into one session bean
> - that way its easier to maintain
>
> > * Instead of using a binding expression for the rendered property,
> >   find the component instance and set it directly there.  This works
> >   because JSF restores the component tree for you, including the
> >   value of all the directly set attributes.  (Anything where you've
> >   used an expression is going to cause that expression to be
> >   re-evaluated, as we have seen.)
> >
> i might be missing the idea, but in my case the rendering of certain
> command buttons depends on the state of several interacting request beans
> so its not just one component that is used for evaluation
>
> Marek
>
> Thank you all for the feedback, though I will still argue this behaviour of
> myfaces does not seem logical :) i mean maybe i should submit it for a
> wishlist? (unless someone is sure its not going to work because of some
> core logic that cant be changed)
>
>

Re: Action not called when the value for rendered attribute changes

Posted by Marek Zachara <ma...@telperion.pl>.
On Sunday 24 December 2006 00:11, Craig McClanahan wrote:
> On 12/23/06, Marek Zachara <ma...@telperion.pl> wrote:
> > certainly, though it boils down to extremely simple scenario:
> >
> > bean1 (scope="request"):
> > public String testAction() {
> >         System.out.print("Test Action");
> >         return null;
> > }
> >
> > bean2 (scope="request"):
> > private boolean show = false;
> > public setShow() {
> >         this.showMe = true;
> > }
> > public boolean showMe() {
> >         return this.showMe;
> > }
> >
> > jsf page:
> > ....
> > some code that calls bean2.setShow
> > ....
> > <h:commandButton value="Test Me" action="#{bean1.testAction}"
> > rendered="#{bean2.showMe}" />
> >
> >
> > the above is enough to reporoduce the behaviour (nothing will
> > be written in the log/stdout
>
> Actually, this behavior is "by design" and you need to adapt your
> application logic to it.
>
> The "rendered" property is used in *two* places  for command and input
> components (including <h:commandButton> here):
>
> * During Render Response, to determine whether or not to render
>   the component at all.
>
> * During Apply Request Values on the subsequent postback, to
>   determine whether or not the input value should be decoded
>   and processed.  (The "disabled" property, when present, is also
>   a part of this test but isn't relevant for your example use case.)
>
> It's the second one that is biting you with your current logic -- as the
> component tree is getting reconstructed during Restore View, the "#{
> bean2.showMe}" expression is evaluated (creating a new instance of Bean2)
> ... and that returns your default value of "false".
>
> To do what you are trying to do, you need to have the calculated value for
> the "showMe" property survive from one request to the next.  A few ways to
> make that happen:
>
> * As suggested, use <t:saveState> (although I'm on record
>   as not liking this, because it mixes business logic and presentation
>   logic in the page :-).
>
> * Put bean2 in session scope instead of request scope.  That
>   way, the previously set value will be remembered.
>
this solution does not seem practical in my case as i have quite a few
beans that would have to be put into session scope - and i certainly
dont want to have them 'hanging around' all the time. So i have
gathered all this rendering attributes into one session bean 
- that way its easier to maintain

> * Instead of using a binding expression for the rendered property,
>   find the component instance and set it directly there.  This works
>   because JSF restores the component tree for you, including the
>   value of all the directly set attributes.  (Anything where you've
>   used an expression is going to cause that expression to be
>   re-evaluated, as we have seen.)
>
i might be missing the idea, but in my case the rendering of certain
command buttons depends on the state of several interacting request beans
so its not just one component that is used for evaluation

Marek

Thank you all for the feedback, though I will still argue this behaviour of 
myfaces does not seem logical :) i mean maybe i should submit it for a 
wishlist? (unless someone is sure its not going to work because of some
core logic that cant be changed)


Re: Action not called when the value for rendered attribute changes

Posted by Mike Kienenberger <mk...@gmail.com>.
On 12/23/06, Craig McClanahan <cr...@apache.org> wrote:
> * As suggested, use <t:saveState> (although I'm on record
>   as not liking this, because it mixes business logic and presentation
>   logic in the page :-).

It's a matter of perspective.

I don't see it as business logic.   All t:saveState is doing is
changing the value from request-scoped to page-scoped.    Page scope
is a missing intrinsic feature of JSF.   Changing the value to session
scope is overkill.

Re: Action not called when the value for rendered attribute changes

Posted by Craig McClanahan <cr...@apache.org>.
On 12/23/06, Marek Zachara <ma...@telperion.pl> wrote:
>
>
> certainly, though it boils down to extremely simple scenario:
>
> bean1 (scope="request"):
> public String testAction() {
>         System.out.print("Test Action");
>         return null;
> }
>
> bean2 (scope="request"):
> private boolean show = false;
> public setShow() {
>         this.showMe = true;
> }
> public boolean showMe() {
>         return this.showMe;
> }
>
> jsf page:
> ....
> some code that calls bean2.setShow
> ....
> <h:commandButton value="Test Me" action="#{bean1.testAction}"
> rendered="#{bean2.showMe}" />
>
>
> the above is enough to reporoduce the behaviour (nothing will
> be written in the log/stdout


Actually, this behavior is "by design" and you need to adapt your
application logic to it.

The "rendered" property is used in *two* places  for command and input
components (including <h:commandButton> here):

* During Render Response, to determine whether or not to render
  the component at all.

* During Apply Request Values on the subsequent postback, to
  determine whether or not the input value should be decoded
  and processed.  (The "disabled" property, when present, is also
  a part of this test but isn't relevant for your example use case.)

It's the second one that is biting you with your current logic -- as the
component tree is getting reconstructed during Restore View, the "#{
bean2.showMe}" expression is evaluated (creating a new instance of Bean2)
... and that returns your default value of "false".

To do what you are trying to do, you need to have the calculated value for
the "showMe" property survive from one request to the next.  A few ways to
make that happen:

* As suggested, use <t:saveState> (although I'm on record
  as not liking this, because it mixes business logic and presentation
  logic in the page :-).

* Put bean2 in session scope instead of request scope.  That
  way, the previously set value will be remembered.

* Instead of using a binding expression for the rendered property,
  find the component instance and set it directly there.  This works
  because JSF restores the component tree for you, including the
  value of all the directly set attributes.  (Anything where you've
  used an expression is going to cause that expression to be
  re-evaluated, as we have seen.)

Craig

Re: Action not called when the value for rendered attribute changes

Posted by Marek Zachara <ma...@telperion.pl>.
certainly, though it boils down to extremely simple scenario:

bean1 (scope="request"):
public String testAction() {
	System.out.print("Test Action");
	return null;
}

bean2 (scope="request"):
private boolean show = false;
public setShow() {
	this.showMe = true;
}
public boolean showMe() {
	return this.showMe;
}

jsf page:
....
some code that calls bean2.setShow
....
<h:commandButton value="Test Me" action="#{bean1.testAction}" 
rendered="#{bean2.showMe}" />


the above is enough to reporoduce the behaviour (nothing will 
be written in the log/stdout



On Saturday 23 December 2006 21:44, Behrang Saeedzadeh wrote:
> Marek,
>
> Could you please post the source code for your page and backing beans?
> It is very difficult to guess what is probably wrong in your case.
>
> Also consider adding a <h:messages showDetail="true" /> to your page.
> That might help as well.
>
> - Behi
>
> On 12/23/06, Marek Zachara <ma...@telperion.pl> wrote:
> > Hello,
> >
> > I have a scenario which seems to be trival, so i guess i must have missed
> > something obvious, but still i cant seem to find a solution
> >
> > on a page i have a sample form with a command button connected to the
> > backing beans:
> > <h:commandButton value="Test Me" action="#{bean1.testAction}"
> > rendered="#{bean2.showMe}" />
> >
> > both bean1 and bean2 have scope=request
> >
> > now, bean2 is created during the generation of the page,
> > and method isShowMe() returns true;
> >
> > the button is displayed. i can click it, though to my surprise
> > the action is not called (i have put a log message in testAction to
> > verify that). Even the bean1 itself is not created.
> >
> > as i have found out, this is due to the rendered attribute - when
> > i set it to true or bind it to a some method in session bean, everything
> > works fine. The bean2 is destroyed after generation of the page with the
> > button, so it seems as it is trying to access it nevertheless after
> > the button is clicked, fails and as a result the whole action fails.
> > I have tried it also with attribute immediate="true" , but with no
> > success either.
> >
> > i will really be glad if anyone can help me out :)
> >
> > Marek

Re: Action not called when the value for rendered attribute changes

Posted by Behrang Saeedzadeh <be...@gmail.com>.
Marek,

Could you please post the source code for your page and backing beans?
It is very difficult to guess what is probably wrong in your case.

Also consider adding a <h:messages showDetail="true" /> to your page.
That might help as well.

- Behi


On 12/23/06, Marek Zachara <ma...@telperion.pl> wrote:
> Hello,
>
> I have a scenario which seems to be trival, so i guess i must have missed
> something obvious, but still i cant seem to find a solution
>
> on a page i have a sample form with a command button connected to the backing
> beans:
> <h:commandButton value="Test Me" action="#{bean1.testAction}"
> rendered="#{bean2.showMe}" />
>
> both bean1 and bean2 have scope=request
>
> now, bean2 is created during the generation of the page,
> and method isShowMe() returns true;
>
> the button is displayed. i can click it, though to my surprise
> the action is not called (i have put a log message in testAction to verify
> that). Even the bean1 itself is not created.
>
> as i have found out, this is due to the rendered attribute - when
> i set it to true or bind it to a some method in session bean, everything
> works fine. The bean2 is destroyed after generation of the page with the
> button, so it seems as it is trying to access it nevertheless after
> the button is clicked, fails and as a result the whole action fails.
> I have tried it also with attribute immediate="true" , but with no
> success either.
>
> i will really be glad if anyone can help me out :)
>
> Marek
>


-- 
"Science is a differential equation. Religion is a boundary condition"
- Alan Turing

Behrang Saeedzadeh
http://www.jroller.com/page/behrangsa
http://my.opera.com/behrangsa