2

I'm using Mojarra 2.0.3 on JBoss 6.1.0 final. I'm having a problem with the value setter method for an h:selectBooleanCheckbox not being called if conditional rendering is specified in the tag.

Specifically:

JSF:

<h:selectBooleanCheckbox value="#{somebean.checked}" rendered="#{somebean.render}" />

Example bean code:

private Boolean checked = new Boolean(false);

public Boolean getChecked() {return checked;}

public void setChecked(Boolean checked) {this.checked = checked;}

public boolean getRender() {return true;}

The problem is that the setChecked() method is never called when the form is submitted. If I remove the "rendered" attribute, the setter will be called as expected. It's only when the tag is conditionally rendered that it is not processed on submit. The getter is called normally in either case.

If I set a valueChangeListener, this is also not invoked if the selectBooleanCheckbox is conditionally rendered. Finally, enclosing the h:selectBooleanCheckbox tag in a container like an :panelGrid and setting the conditional rendering on the "outside" component results in the same behavior. It seems that the checkbox won't be processed if it is conditionally rendered.

This seems like kind of a basic thing, so I'm assuming there is something I'm missing. Does anyone have any similar experience with this?

UPDATE: The managed bean in this case is a CDI ConversationScoped bean. Further debugging seemed to suggest that another instance of the bean instantiated and used somewhere in the JSF lifecycle. So I modified the bean to set the conversation to non-transient in the postConstruct method. This caused JSF to throw the following exception while evaluating the EL expression used in the "rendered" attribute:

23:41:12,179 WARNING[javax.enterprise.resource.webcontainer.jsf.lifecycle] /admin/edit_user_profile.xhtml @41,72 rendered="#{profileEditor.isCurrentUser}": java.lang.IllegalStateException: javax.el.ELException: /admin/edit_user_profile.xhtml @41,72 rendered="#{profileEditor.isCurrentUser}": java.lang.IllegalStateException
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:111) [:2.0.3-]
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:190) [:2.0.3-]
    at javax.faces.component.UIComponentBase.isRendered(UIComponentBase.java:417) [:2.0.3-]
.
.
.
Caused by: java.lang.IllegalStateException
    at com.sun.faces.context.FacesContextImpl.assertNotReleased(FacesContextImpl.java:635) [:2.0.3-]
    at com.sun.faces.context.FacesContextImpl.getExternalContext(FacesContextImpl.java:135) [:2.0.3-]
    at com.sgi.tds.web.admin.beans.TdsAdminBean.getCurrentUser(TdsAdminBean.java:36) [:]
    at com.sgi.tds.web.admin.beans.UserProfileEditorBean.getIsCurrentUser(UserProfileEditorBean.java:153) [:]
    at com.sgi.tds.web.admin.beans.UserProfileEditorBean$Proxy$_$$_WeldClientProxy.getIsCurrentUser(UserProfileEditorBean$Proxy$_$$_WeldClientProxy.java) [:]
wittich
  • 2,079
  • 2
  • 27
  • 50
platapapin
  • 43
  • 1
  • 6
  • Actually I'm having the same problem with deep nests in Primefaces, renders fine and fails to render (always false). Generally speaking Balus is right--but I have noticed this behavior in deep nests. I'd be interested in a complete simple test case to replicate it, I was blaming rendering order in the Primefaces engine, but it might be something more subtle. – Daniel B. Chapman Sep 20 '11 at 20:58

1 Answers1

2

As part of attack safeguard, the rendered attribute is re-evaluated when JSF postprocesses the form submit. That it evaluates false in your particular case can only mean that your bean is request scoped and that you didn't preserve the attribute value in bean's (post)constructor.

If you can't preserve it, then you need to put the bean in the view scope.

@ManagedBean
@ViewScoped
public class Somebean {

    // ...
}

This way the bean instance lives as long as you're interacting with the same view. See also this related question/answer: commandButton/commandLink/ajax action/listener method not invoked or input value not updated

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks for your answer. The bean is actually a CDI RequestScoped bean, which is *supposed* to be equivalent to JSF ViewScoped but doesn't always behave that way. FWIW, I observe the same behavior if I include the "disabled" attribute rather than "rendered", which would seem to indicate that something else is going on here. – platapapin Sep 20 '11 at 21:09
  • No, it isn't supposed to be. Use either JSF `@ViewScoped` or CDI `@ConversationScoped` or preserve the condition yourself in bean's (post)constructor. The `disabled` attribute problem is not different. It has the same root cause, it's also re-evaluated during apply request values phase. See also the related link. – BalusC Sep 20 '11 at 21:42
  • I'm sorry, my bad. I wrote RequestScoped when I meant ConversationScoped. The backing bean is a CDI ConversationScoped bean. Anyway, I modified the bean to set the conversation as non-transient in the PostConstruct, since further debugging suggested that JSF was getting another copy of the bean during processing. Now I've got JSF throwing an IllegalStateException when trying to get the ExternalContext in the bean code used to evaluate the "rendered" in question. I'll post the stack trace as a response to this post ASAP. – platapapin Sep 21 '11 at 04:01
  • Sorry, I don't have hands-on experience with CDI nor have in depth knowledge about its working, so I wouldn't be able to tell what the possible causes for that are. However, the symptom of getting another copy of the bean sounds very familiar: a `@ViewScoped` bean exposes the same symptom whenever you bind one of its properties by EL to a tag handler (which runs during view build time). See also http://balusc.blogspot.com/2011/09/communication-in-jsf-20.html#ViewScopedFailsInTagHandlers I'd try again with the smallest possible view/bean test example without any other tags/components. – BalusC Sep 21 '11 at 04:06
  • thanks very much for all your help. The problem is indeed caused by JSF instantiating another instance of the managed bean during processing of the post. Since this new copy of the bean is used "as is", without calling the setters for the instance variables, the behaviour is incorrect at best. I'll take a look at your other posts on the subject to see if I can come up with a workaround. But I can't believe that this is considered a "feature" of the JSF implementation. – platapapin Sep 21 '11 at 14:59
  • You're welcome. As to the "feature", the `@ViewScoped` problem is really a chicken-egg issue. You can't reuse an existing view scoped bean while rebuilding the view as it is stored in there. – BalusC Sep 21 '11 at 15:01