【问题标题】:JSF selectBooleanCheckbox not calling the associated setter method if it is conditionally rendered如果有条件渲染,JSF selectBooleanCheckbox 不会调用关联的 setter 方法
【发布时间】:2011-11-21 10:08:55
【问题描述】:

我在 JBoss 6.1.0 final 上使用 Mojarra 2.0.3。如果在标签中指定了条件渲染,我遇到了 h:selectBooleanCheckbox 的 value setter 方法的问题。

具体来说:

JSF:

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

示例 bean 代码:

private Boolean checked = new Boolean(false);

public Boolean getChecked() {return checked;}

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

public boolean getRender() {return true;}

问题是提交表单时永远不会调用 setChecked() 方法。如果我删除“rendered”属性,setter 将按预期调用。只有当标签被有条件地呈现时,它才不会在提交时被处理。无论哪种情况,都会正常调用 getter。

如果我设置了 valueChangeListener,如果 selectBooleanCheckbox 有条件地呈现,则也不会调用它。最后,将 h:selectBooleanCheckbox 标记包含在像 :panelGrid 这样的容器中并在“外部”组件上设置条件渲染会导致相同的行为。如果有条件渲染,似乎不会处理复选框。

这似乎是一种基本的东西,所以我假设我缺少一些东西。有没有人有类似的经历?

更新:本例中的托管 bean 是 CDI ConversationScoped bean。进一步的调试似乎表明 bean 的另一个实例在 JSF 生命周期的某个地方实例化并使用了。所以我修改了 bean 以在 postConstruct 方法中将对话设置为非瞬态。这导致 JSF 在评估“rendered”属性中使用的 EL 表达式时抛出以下异常:

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) [:]

【问题讨论】:

  • 实际上我在 Primefaces 中的深层嵌套也有同样的问题, 渲染得很好,而 渲染失败(总是假的)。一般来说,巴鲁斯是对的——但我在深巢中注意到了这种行为。我对复制它的完整简单测试用例感兴趣,我指责 Primefaces 引擎中的渲染顺序,但它可能更微妙。

标签: jsf


【解决方案1】:

作为攻击防护的一部分,rendered 属性会在 JSF 后处理表单提交时重新评估。它在您的特定情况下评估 false 仅意味着您的 bean 是请求范围的,并且您没有在 bean 的(post)构造函数中保留属性值。

如果不能保存,则需要将bean放入视图范围内。

@ManagedBean
@ViewScoped
public class Somebean {

    // ...
}

这样,只要您与同一个视图交互,bean 实例就会一直存在。另请参阅此相关问题/答案:commandButton/commandLink/ajax action/listener method not invoked or input value not updated

【讨论】:

  • 感谢您的回答。该 bean 实际上是一个 CDI RequestScoped bean,它假定等同于 JSF ViewScoped,但并不总是这样。 FWIW,如果我包含“禁用”属性而不是“渲染”属性,我会观察到相同的行为,这似乎表明这里发生了其他事情。
  • 不,不应该这样。使用 JSF @ViewScoped 或 CDI @ConversationScoped 或自己在 bean 的(后)构造函数中保留条件。 disabled 属性问题也不例外。它具有相同的根本原因,它也在应用请求值阶段重新评估。另请参阅相关链接。
  • 对不起,我的错。当我指的是 ConversationScoped 时,我写了 RequestScoped。支持 bean 是 CDI ConversationScoped bean。无论如何,我修改了 bean 以在 PostConstruct 中将对话设置为非瞬态,因为进一步的调试表明 JSF 在处理期间获取了 bean 的另一个副本。现在,当我试图在用于评估有问题的“渲染”的 bean 代码中获取 ExternalContext 时,JSF 抛出了 IllegalStateException。我会尽快发布堆栈跟踪作为对这篇文章的回应。
  • 抱歉,我没有 CDI 的实际操作经验,也没有深入了解它的工作原理,所以我无法说出可能的原因是什么。但是,获取另一个 bean 副本的症状听起来很熟悉:每当您通过 EL 将它的一个属性绑定到标记处理程序(在视图构建期间运行)时,@ViewScoped bean 就会暴露相同的症状。另请参阅balusc.blogspot.com/2011/09/… 我会在没有任何其他标签/组件的情况下使用尽可能小的视图/bean 测试示例再试一次。
  • 非常感谢您的帮助。该问题确实是由 JSF 在处理帖子期间实例化托管 bean 的另一个实例引起的。由于 bean 的这个新副本是“按原样”使用的,没有调用实例变量的设置器,因此行为充其量是不正确的。我会看看你关于这个主题的其他帖子,看看我是否能想出一个解决方法。但我不敢相信这被认为是 JSF 实现的“特性”。
猜你喜欢
  • 1970-01-01
  • 2012-11-28
  • 2012-06-18
  • 2012-08-31
  • 2020-12-20
  • 2014-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多