这个问题可能更像“概念”或“我不懂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>
这有效,但显然是一个丑陋的黑客/解决方法。
处理这种情况的正确方法是什么?或者我所做的完全错了?
答案 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