集合操作的非法语法:如何告诉JSF我不“想要”一个setter

时间:2014-06-23 16:30:33

标签: jsf jsf-2 primefaces el jsf-2.2

这个问题可能更像“概念”或“我不懂JSF”。

我的情景: 我有一个JSF页面(index.xhtml),我使用p:accordionPanel(但我认为它不重要的是什么组件)。我想要做的是设置它的activeIndexes

<p:accordionPanel multiple="true" activeIndex="#{myController.getActiveIndexesForSections('whatever')}">
// bla bla...
</p:accordionPanel>

支持bean中的(简化)方法:

public String getActiveIndexesForSections(String holderName){
    String activeSections = "";
    for(Section s : sectionMap.get(holderName)){
        if (s.isActive())
        //add to the string
    }
    return activeSections;
}

现在这在普通页面加载时效果很好。

但是,如果我点击p:commandButton(带ajax=false)(或其他任何“将”数据“发送回服务器的话),我会得到以下异常:

/WEB-INF/tags/normalTextSection.xhtml @8,112 activeIndex="#{myController.getActiveIndexesForSections(name)}": Illegal Syntax for Set Operation
// bla..
Caused by: javax.el.PropertyNotWritableException: Illegal Syntax for Set Operation

在谷歌搜索/阅读错误消息后,我发现我需要setter

首先:我不想要一个setter - 我真的需要一个或者有办法告诉JSF我不想要这个“行为”。

其次我意识到提供一个setter并不“那么容易”,因为我的方法有一个参数(所以public void setActiveIndexesForSections(String name, String activeIndexes)public void setActiveIndexesForSections(String name)不起作用)。 我最终想出的是:

创建(通用)“Pseudo-Property-class”:

// just a dummy class since the class is recreated at every request
public class Property<T> implements Serializable {

    private T val;

    public Property(T val) {
        this.val= val;
    }

    public T getVal() {
        return val;
    }

            //no need to do anyhting
    public void setVal(T val) {
    }
}

更改bean方法:

public Property<String> getActiveIndexesForSections(String holderName){
    String activeSections = "";
    for(Section s : sectionMap.get(holderName)){
        if (s.isActive())
        //add to the string
    }
    return new Property<String>(activeSections);
}

并从index.xhtml

调用它
<p:accordionPanel multiple="true" activeIndex="#{myController.getActiveIndexesForSections('whatever').val}">
// bla bla...
</p:accordionPanel>

这有效,但显然是一个丑陋的黑客/解决方法。

处理这种情况的正确方法是什么?或者我所做的完全错了?

1 个答案:

答案 0 :(得分:20)

需要setter来记住提交表单时的活动索引。基本上,您需要将其绑定为值表达式(使用属性),而不是作为方法表达式(如操作方法)绑定,也不能绑定到不可修改的集合(如activeIndex="#{param.tab}")。与输入值完全一样。从技术上讲,你确实这样做“完全错误”;)

然而,要求是理解的。鉴于您对更改的活动索引真的不感兴趣,因此希望在每个表单提交时将它们重置为默认值,那么您可以通过在<c:set>的帮助下将结果存储为请求属性来绕过它。这样你就会欺骗EL在请求属性映射中设置它而不是意图的bean属性。

<c:set var="activeIndex" value="#{myController.getActiveIndexesForSections('whatever')}" scope="request" />
<p:accordionPanel multiple="true" activeIndex="#{activeIndex}">
    <!-- bla bla... -->
</p:accordionPanel>

在封面下,它基本上会作为setter操作进行externalContext.getRequestMap().put("activeIndex", value),这显然会起作用。


更新:在检查source code of AccordionPanel component时,我看到了另一种解决方法,因为activeIndex属性评估时rendered不会被设置{ {1}}。因此,只需更改false属性即可:在更新模型值阶段(第4阶段)评估rendered

false