JSF 2.0: пользовательский компонент на основе Java + таблица html + лицевые панели = модель данных не обновлена

У меня возникают проблемы с корректным обновлением модели данных HtmlDataTable с помощью JSF 2.0 и Facelets.

Я создал собственный компонент на основе 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}"/>

Мой класс управляемого компонента содержит следующее

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

Спасибо за вашу помощь.


person mikic    schedule 19.04.2010    source источник


Ответы (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 );

Вот проект, демонстрирующий программное использование JSF 2.0.

person lexicore    schedule 19.04.2010
comment
Привет, спасибо за предложение, однако использование setValueExpression вместо метода setValue не решило проблему. При отправке формы модель данных не обновляется. Любое другое предложение? - person mikic; 20.04.2010
comment
Это сложная настройка, многое может пойти не так. То, что я указал, в любом случае является проблемой. Попробуйте выполнить трассировку/отладку, установите точку останова в методе декодирования средства визуализации элемента управления вводом текста и трассируйте оттуда. - person lexicore; 20.04.2010