我有一个实现UIInput
的自定义组件,该组件需要保存一些状态信息,以便以后在回发请求中重用。独立使用它可以很好地工作,但是回发会在<ui:repeat>
中找到最新渲染的数据行的保存状态。动作调用的日志输出为
INFORMATION: myData is "third foo"
INFORMATION: myData is "third foo"
INFORMATION: myData is "third foo"
INFORMATION: ok action
我希望的地方
INFORMATION: myData is "first foo"
INFORMATION: myData is "second foo"
INFORMATION: myData is "third foo"
INFORMATION: ok action
我知道myComponent
是ui:repeat
内部的单个实例。那么保存组件状态以便正确地为数据集中的每一行还原的最佳方法是什么?
我的XHTML表单:
<h:form>
<ui:repeat var="s" value="#{myController.data}">
<my:myComponent data="#{s}"/>
</ui:repeat>
<h:commandButton action="#{myController.okAction}" value="ok">
<f:ajax execute="@form" render="@form"/>
</h:commandButton>
</h:form>
我的豆子:
@Named
@ViewScoped
public class MyController implements Serializable {
private static final long serialVersionUID = -2916212210553809L;
private static final Logger LOG = Logger.getLogger(MyController.class.getName());
public List<String> getData() {
return Arrays.asList("first","second","third");
}
public void okAction() {
LOG.info("ok action");
}
}
复合组件XHTML代码:
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:cc="http://xmlns.jcp.org/jsf/composite">
<cc:interface componentType="myComponent">
<cc:attribute name="data"/>
</cc:interface>
<cc:implementation>
<h:panelGrid columns="2">
<h:outputLabel value="cc.attrs.data"/>
<h:outputText value="#{cc.attrs.data}"/>
<h:outputLabel value="cc.myData"/>
<h:outputText value="#{cc.myData}"/>
</h:panelGrid>
</cc:implementation>
</ui:component>
复合组件支持类:
@FacesComponent
public class MyComponent extends UIInput implements NamingContainer {
private static final Logger LOG=Logger.getLogger(MyComponent.class.getName());
public String calculateData() {
return String.format("%s foo", this.getAttributes().get("data") );
}
public String getMyData() {
return (String)getStateHelper().get("MYDATA");
}
public void setMyData( String data ) {
getStateHelper().put("MYDATA", data);
}
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
this.setMyData( calculateData() );
super.encodeBegin(context);
}
@Override
public void processDecodes(FacesContext context) {
super.processDecodes(context);
LOG.log(Level.INFO, "myData {0}", getMyData() );
}
}
只是尝试重现您的问题,是的,现在我终于明白了您的意思。您只想使用JSF组件状态作为计算变量的某种视图范围。我能理解观察到的行为确实是出乎意料的。