JSF 2.0:基于java的自定义组件+ html表+ facelets =数据模型未更新

时间:2010-04-19 16:35:45

标签: jsf glassfish facelets custom-component jsf-2

我无法通过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完成的。

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

你的问题可能就在这里:

myNewText.setValue("#{row[" + i + "]}");

您在此处设置字符串值,而不是值绑定。您需要执行以下操作:

Application application = facesContext.getApplication();
ExpressionFactory expressionFactory = application
        .getExpressionFactory();
...
ValueExpression valueExpression = expressionFactory
            .createValueExpression(facesContext.getELContext(),
                    "#{row[" + i + "]}", String.class);
myNewText.setValueExpression("value", valueExpression );

Here's an a project演示了JSF 2.0的程序化用法。