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

发布于 2024-08-29 09:55:28 字数 3183 浏览 9 评论 0原文

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

感谢您的帮助。

I'm having problems getting the data model of a HtmlDataTable to be correctly updated by JSF 2.0 and Facelets.

I have created a custom Java-based component that extends HtmlDataTable and dynamically adds columns in the encodeBegin method.

@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);
}

My test page contains the following

    <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}"/>

My managed bean class contains the following

@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;
}

When invoked, the page is correctly rendered with a table made of 3 columns (added at runtime) and 2 rows (as my data model has 2 rows). However when the user enter some data in the input fields and then click the submit button, the model is not correctly updated and therefore the mergeInput() method creates a sequence of empty strings which is rendered on the same page.

I have added some logging to the decode() method of my custom component and I can see that the parameters entered by the user are being posted back with the request, however these parameters are not used to update the data model.

If I update the encodeBegin() method of my custom component as follow

@Override
public void encodeBegin(FacesContext context) throws IOException
{
  super.encodeBegin(context);
}

and I update the test page as follow

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

the page is correctly rendered and this time when the user enters data and submits the form, the underlying data model is correctly updated and the mergeInput() method creates a sequence of strings with the user data.

Why does the test case with columns declared in the facelet page works correctly (ie the data model is correctly updated by JSF) where the same does not happen when the columns are created at runtime using the encodeBegin() method?

Is there any method I need to invoke or interface I need to extend in order to ensure the data model is correctly updated?

I am using this test case to address the issue that is appearing in a much more complex component, therefore I can't achieve the same functionality using a facelet composite component.

Please note that this has been done using NetBeans 6.8, JRE 1.6.0u18, GlassFish 3.0.

Thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

陈独秀 2024-09-05 09:55:28

您的问题可能就在这里:

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 );

这是一个项目,它演示了 JSF 2.0 的编程用法。

Your problem is probably here:

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

You're setting a string value here, not value binding. You'll need to do something like:

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 which demonstrates programmatic usage of JSF 2.0.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文