我在让 JSF 2.0 和 Facelets 正确更新 HtmlDataTable 的数据模型时遇到问题。
我创建了一个自定义的基于 Java 的组件,它扩展了 HtmlDataTable 并在 encodeBegin 方法中动态添加列。
@Override
public void encodeBegin(FacesContext context) throws IOException
{
if (this.findComponent("c0") == null)
{
for (int i = 0; i < 3; i++)
{
HtmlColumn myNewCol = new HtmlColumn();
myNewCol.setId("c" + i);
HtmlInputText myNewText = new HtmlInputText();
myNewText.setId("t" + i);
myNewText.setValue("#{row[" + i + "]}");
myNewCol.getChildren().add(myNewText);
this.getChildren().add(myNewCol);
}
}
super.encodeBegin(context);
}
我的测试页面包含以下内容
<h:form id="fromtb">
<test:MatrixTest id="tb" var="row" value="#{MyManagedBean.model}">
</test:MatrixTest>
<h:commandButton id="btn" value="Set" action="#{MyManagedBean.mergeInput}"/>
</h:form>
<h:outputText id="mergedInput" value="#{MyManagedBean.mergedInput}"/>
我的托管 bean 类包含以下内容
@ManagedBean(name="MyManagedBean")
@SessionScoped
public class MyManagedBean
{
private List model = null;
private String mergedInput = null;
public MyManagedBean() {
model = new ArrayList();
List myFirst = new ArrayList();
myFirst.add("");
myFirst.add("");
myFirst.add("");
model.add(myFirst);
List mySecond = new ArrayList();
mySecond.add("");
mySecond.add("");
mySecond.add("");
model.add(mySecond);
}
public String mergeInput()
{
StringBuffer myMergedInput = new StringBuffer();
for (Object object : model)
{
myMergedInput.append(object);
}
setMergedInput(myMergedInput.toString());
return null;
}
public List getModel() {
return model;
}
public void setModel(List model) {
this.model = model;
}
public String getMergedInput() {
return mergedInput;
}
public void setMergedInput(String mergedInput) {
this.mergedInput = mergedInput;
}
调用时,页面会正确呈现一个由 3 列(在运行时添加)和 2 行(因为我的数据模型有 2 行)组成的表。但是,当用户在输入字段中输入一些数据然后单击提交按钮时,模型没有正确更新,因此 mergeInput() 方法会创建一个在同一页面上呈现的空字符串序列。
我在自定义组件的 decode() 方法中添加了一些日志记录,我可以看到用户输入的参数正在随请求一起回发,但是这些参数不用于更新数据模型。
如果我更新自定义组件的 encodeBegin() 方法如下
@Override
public void encodeBegin(FacesContext context) throws IOException
{
super.encodeBegin(context);
}
我更新测试页面如下
<test:MatrixTest id="tb" var="row" value="#{MyManagedBean.model}">
<h:column id="c0"><h:inputText id="t0" value="#{row[0]}"/></h:column>
<h:column id="c1"><h:inputText id="t1" value="#{row[1]}"/></h:column>
<h:column id="c2"><h:inputText id="t2" value="#{row[2]}"/></h:column>
</test:MatrixTest>
页面被正确呈现,这一次当用户输入数据并提交表单时,底层数据模型被正确更新,mergeInput() 方法使用用户数据创建了一系列字符串。
为什么带有在 facelet 页面中声明的列的测试用例可以正常工作(即 JSF 正确更新数据模型),而在运行时使用 encodeBegin() 方法创建列时不会发生同样的情况?
是否需要调用任何方法或扩展接口以确保正确更新数据模型?
我正在使用这个测试用例来解决出现在更复杂的组件中的问题,因此我无法使用 facelet 复合组件实现相同的功能。
请注意,这是使用 NetBeans 6.8、JRE 1.6.0u18、GlassFish 3.0 完成的。
谢谢你的帮助。