集合操作的非法语法:如何告诉JSF我“不想要"塞特犬 [英] Illegal Syntax for Set Operation: How to tell JSF I don't "want" a setter

查看:122
本文介绍了集合操作的非法语法:如何告诉JSF我“不想要"塞特犬的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题可能更多是概念性"或我不了解JSF"类型.

This question may be more of the type "conceptual" or "I don't understand JSF".

我的情况: 我有一个JSF Page(index.xhtml),我在其中使用p:accordionPanel(但我认为它是什么组件并不重要).我要设置的是activeIndexes.

My scenario: I have a JSF Page (index.xhtml) where I use a p:accordionPanel (but I don't think it matters what component it is). What I want to do is to set the activeIndexes of it.

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

以及后备bean中的(简化)方法:

And the (simplified) method in the backing bean:

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

现在,这在正常的页面加载中可以正常工作.

Now this works just fine on a normal page load.

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

But if I click on a p:commandButton (with ajax=false) (or anything else which "sends" data back to the server I guess) - I get the following exception:

/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.

After some googling / reading the error message I found that I need a setter.

首先:我不需要二传手-我真的需要一个二传手吗,或者有办法告诉JSF我不想要这个行为".

First of all: I don't want a setter - do I really need one or is there a way to tell JSF I don't want this "behavior".

第二,我意识到提供一个setter并不是那么容易,因为我的方法有一个参数(所以public void setActiveIndexesForSections(String name, String activeIndexes)public void setActiveIndexesForSections(String name)无效). 我最终想到的是:

Second I realized that it's not that "easy" to provide a setter, because my method has a parameter (so public void setActiveIndexesForSections(String name, String activeIndexes) or public void setActiveIndexesForSections(String name)won't work). What I came up with in the end is:

创建(通用)伪属性类":

Create a (generic) "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>

这可行,但显然是一个丑陋的破解/解决方法.

This works but obviously is a ugly hack/workaround.

处理这种情况的正确方法是什么?还是我在做的事完全是错误的?

What is the proper way to handle a situation like this? Or is what I'm doing simply completely wrong?

推荐答案

设置程序需要记住提交表单时的活动索引.基本上,您需要将其绑定为值表达式(具有属性),而不是方法表达式(例如action方法),也不能绑定到不可修改的集合(例如activeIndex="#{param.tab}").就像输入值一样.从技术上讲,您确实在做完全错误";)

The setter is needed to remember the active indexes as they were when the form is submitted. Basically, you need to bind it as a value expression (with a property), not as a method expression (like an action method), nor to an unmodifiable collection (like activeIndex="#{param.tab}"). Exactly like as with input values. Technically, you're indeed doing it "simply completely wrong" ;)

但是该要求已被理解.鉴于您实际上对更改后的活动索引不感兴趣,因此希望在每次提交表单时将其重置为默认值,然后可以通过在<c:set>的帮助下将结果存储为请求属性来绕过它.这样,您将欺骗EL将其设置在请求属性映射中,而不是intented bean属性中.

The requirement is however understood. Given that you're really not interested in the changed active indexes, and thus want to reset them to defaults on every form submit, then you can bypass it by storing the result as a request attribute with help of <c:set>. This way you will fool EL to set it in the request attribute map instead of the intented bean property.

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

在幕后,基本上它将执行externalContext.getRequestMap().put("activeIndex", value)作为二传手操作,这显然会起作用.

Under the covers, it will basically do externalContext.getRequestMap().put("activeIndex", value) as setter operation, which will obviously just work.

更新:检查

Update: upon inspecting the source code of AccordionPanel component, I saw another workaround given the fact that the activeIndex won't be set when the rendered attribute evaluates false. So just alter the rendered attribute to behave exactly that: evaluate false during update model values phase (the 4th phase).

<p:accordionPanel multiple="true" 
    activeIndex="#{myController.getActiveIndexesForSections('whatever')}"
    rendered="#{facesContext.currentPhaseId.ordinal ne 4}">
    <!-- bla bla... -->
</p:accordionPanel>

这篇关于集合操作的非法语法:如何告诉JSF我“不想要"塞特犬的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆