JSF在渲染后将ViewScoped bean的属性重置回初始值

JSF在渲染后将ViewScoped bean的属性重置回初始值,jsf,primefaces,reset,Jsf,Primefaces,Reset,我有一个可视范围的ManagedBean。这个bean有一个布尔属性,它控制是否应该显示数据表。见下文: <p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}"> <p:column> ... </p:column> ... </p:dataTable> @Managed

我有一个可视范围的ManagedBean。这个bean有一个布尔属性,它控制是否应该显示数据表。见下文:

<p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}">   
    <p:column>
        ...
    </p:column>

    ...
</p:dataTable>
@ManagedBean(name = "loc")
@ViewScoped
public class LocationController implements Serializable {
    private boolean renderLocationTable = false;

    // JSF ActionListener.
    public void methodA() {
        if(someCondition) {
            renderLocationTable = true; // this is the only time we should render location table
        }
    }        

    // JSF ActionListener.
    public void methodB() {
        renderLocationTable = false;
    }

    // JSF ActionListener.
    public void methodC() {
        renderLocationTable = false;
    }
}
一旦调用methodA()并满足某些条件,就应该呈现该表;这个很好用。但是,问题是,对于调用的每一个JSF ActionListener方法,我都必须显式地将呈现的布尔值设置回false。见下文:

<p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}">   
    <p:column>
        ...
    </p:column>

    ...
</p:dataTable>
@ManagedBean(name = "loc")
@ViewScoped
public class LocationController implements Serializable {
    private boolean renderLocationTable = false;

    // JSF ActionListener.
    public void methodA() {
        if(someCondition) {
            renderLocationTable = true; // this is the only time we should render location table
        }
    }        

    // JSF ActionListener.
    public void methodB() {
        renderLocationTable = false;
    }

    // JSF ActionListener.
    public void methodC() {
        renderLocationTable = false;
    }
}
我给出了实际ManagedBean和XHTML文件的一个非常小的片段。实际上,这些文件是巨大的,而且很多其他布尔“渲染”标志也在使用。保持这些旗帜的准确性变得越来越困难。另外,每个ActionListener方法现在必须知道所有布尔标志,即使它们与手头的业务无关

这就是我希望能够做到的:

<f:event type="postRenderView" listener="#{loc.resetRenderLocationTable}" />
<p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}">   
    <p:column>
        ...
    </p:column>

    ...
</p:dataTable>
这不是很好吗?不再玩重置布尔变量的游戏。没有更多的测试用例需要确保表不会在不应该显示的时候显示。当适当的JSF ActionListener方法将呈现标志设置为true时,可以将呈现标志设置为true,然后“post-back”调用将该标志重置为false…Perfect。但是,显然,用JSF是无法做到这一点的

那么,有人能解决这个问题吗

谢谢


顺便说一句,这种情况的发生可能比你想象的要多得多。任何时候,只要您有一个使用ActionListeners的带有多个CommandButton的表单,这种情况就可能发生在您身上。如果您曾经使用过JSF ManagedBean,并且您发现自己将布尔标志设置为true或false分散在整个类中,那么这种情况适用于您。

您没有添加primefaces标记,但根据您的代码,我看到您正在使用primefaces。A假设从调用
methodA()
,例如
p:commandButton
。我建议首先创建primefaces远程命令:

<p:remoteCommand name="resetRenderLocationTable">
  <f:setPropertyActionListener value="#{false}" target="#{loc.renderLocationTable}"/>
</p:remoteCommand>

在下一个请求中,您不必担心重置此属性,只需更新数据表。

如果操作侦听器所做的只是重置该标志,那么您可以将各种组件的操作侦听器指向托管bean中的同一方法,不是吗?因此,只有一个地方可以重置该值。为什么不能将用于检查
someCondition
的逻辑移到
preRenderView
事件侦听器中?监听器应该在每次回发时切换变量的状态,而其他ActionListener方法(methodB()和methodC(),如上所示)所做的不仅仅是重置该标志。事实上,methodB()和methodC()与该标志无关,只是如果它们不将该标志设置为false,那么数据表将在不应该显示的时候显示。此外,preRenderView无效的原因是,将methodA()想象成一个非常复杂且资源密集的方法。PreRenderView将在每次回发时执行该代码。按照我的方式,methodA()只在需要时被调用;确定“某些条件”所需的工作量很大。这就是为什么我只想在需要的时候执行代码。这听起来是个好主意!我以前从未听说过“p:remoteCommand”(而且我已经使用Primefaces很长时间了)。我会试试看,然后告诉你。很抱歉延迟回复;直到今天(拉斯维加斯),我整个星期都在度假。
<p:commandButton action="#{loc.methodA()}" update="myDatatable" oncomplete="resetRenderLocationTable()"/>