Соединение составных компонентов JSF2 с использованием ajax

#ajax #jsf-2 #behavior #composite #composite-component

#ajax #jsf-2 #поведение #композитный #составной компонент

Вопрос:

Вот моя (упрощенная) проблема:
у меня есть страница, на которой используются 2 моих составных компонента:
— CCSelection
— CCDisplay

В CCSelection у меня есть список значений, на каждое из которых есть ссылка h: CommandLink.
При нажатии на ссылку компонент CCDiaplay обновляется с использованием выбранного значения.
Для этого CCSelection предоставляет атрибут метода, который напрямую связан с каждой командной ссылкой h:. Значение присваивается методу с помощью атрибута f:.
В компоненте поддержки страницы у меня есть метод (который присваивается CCSelection в качестве атрибута), который устанавливает элемент.
CCDisplay получает это значение через атрибут cc: через средство получения элемента страницы.
Это работает!
Теперь я хочу изменить это поведение.

Я попытался поместить f: ajax для каждой командной строки h: в CCSelection… но если я добавлю @form или @all в атрибут render, ничего не отображается (но вызываются методы setter). Если я добавлю идентификатор UIComponent (страницы) для рендеринга, я получу исключение nullpointerexception, в котором говорится, что свойство не определено для NamingContainer в CCDisplay. Довольно странно, потому что я ничего не менял внутри CCDisplay!

Я думаю, что решение состоит в том, чтобы поместить f: ajax не внутри CCSelection, а на странице.
Таким образом, может быть 2 способа добиться этого:
— CCSelection вызывает событие f: ajax может управлять… но как?
— Использование cc:clientBehaviour для выбора CCS. Но возможно ли настроить таргетинг на более чем 1
компонент (у меня много h: CommandLink, но я хочу только 1 событие).
— Другие способы?

Вот псевдокод

страница.xhtml

 <myComp:ccSelection actionMethod="#{pageBean.select}"
                    render="#{clientIDHelper.clientId['display']}" />
<h:panelGroup id="diplay" binding="#{clientIDHelper.bindings['display']}">
  <myComp:ccDisplay value="#{pageBean.value}" />
</h:panelGroup>
 

Чтобы восстановить полный идентификатор клиента панели, содержащей составной компонент ccDiaplay, я использую технологию clientIDMap, описанную здесь .

PageBean.java

 private String _value;

public String getValue() { return _value; }
public void setValue(String value) [ _value = value; }

public void select(String value) {
  setValue(value);
}
 

ccSelection.xhtml

 <cc:interface>
  <cc:attribute method-signature="void selectAction(String)"
                name="actionMethod" />
  <cc:attribute name="render" />
</cc:interface>
<cc:implementation>
  <t:dataTable value="#{cc.values}"
               var="val"
               ...
               >
    <h:column>
       <t:commandLink actionListener="#{cc.selectionValueListener}"
         <f:ajax render="#{cc.attrs.render}" />
         <f:attribute name="value"
                      value="#{val}" />
       </t:commandLink>
    </h:column>
  </t:dataTable>
</cc:implementation>
 

ccSelection.java

 public void selectionValueListener() {
  // recover the attribute value
  String value = event.getComponent().getAttributes().get("value");
  // call the callback method of the page
  FacesContext context = FacesContext.getCurrentInstance();
  MethodExpression method = (MethodExpression) this.getAttributes().get("actionMethod");
  if (method != null)
    method.invoke(context.getELContext(), new Object[] {value});
}
 

Я не думаю, что ccDisplay интересен.

Итак, если я не добавляю тег f: ajax, он работает. Когда я помещаю f:ajax с отображением, указывающим на идентификатор клиента, переданный в param, я получаю сообщение об ошибке при загрузке страницы. Если я изменю рендеринг для @form или @all, вызывается метод pageBean.select, но ccDisplay не обновляется.

Комментарии:

1. Если я хорошо понимаю, вы подозреваете, что если вы деформируете все свои компоненты с помощью тега f: ajax, это должно сработать, но вы не знаете, как обрабатывать событие, сгенерированное командной ссылкой? Если это так, у меня есть идея, вы можете просто деформировать существующий код с помощью ‘<f: ajax event=»click» execute=»#{yourBean.method}»>’ , в вашем методе, просто попытайтесь найти обходной путь для обработки события только при желании. Если вы опубликуете немного кода или псевдо, возможно, мы могли бы помочь больше.

2. На самом деле, событие с помощью f:ajax, вызывается метод. Проблема заключается в том, что render: CCDisplay не отображается при использовании f: ajax, когда render=»@all» или render=»@form».<br/> Если ввести идентификатор компонента в рендер f: ajax, я получаю сообщение об ошибке при загрузке страницы.

Ответ №1:

Я думаю, что вижу небольшую ошибку в page.xhtml. Посмотрите, когда вы создали компонент cc: отобразите, что вы сказали:

 <cc:attribute method-signature="void selectAction(String)" name="actionMethod" />
 

Это означает, что необходим параметр.

Но когда вы вызываете его в page.xhtml, вы делаете это:

 <myComp:ccSelection actionMethod="#{pageBean.select}"...
 

И его вспомогательный метод bean:

 public void select(String value) {
  setValue(value);
}
 

Как вы видите, вспомогательный компонент правильный, но когда вы вызываете компонент на странице, в компонент не передается параметр, и в конце значение никогда не устанавливается.
Я думаю, что это может быть одной из причин.

Чтобы исправить это, я думаю, вам следует каким-то образом передать значение:

 <myComp:ccSelection actionMethod="#{pageBean.select(???Selected value

???)}"...
 

Комментарии:

1. Спасибо за ответ. Насколько я знаю, вы не можете передавать напрямую параметры, которые вы предлагаете. Тем не менее, он работает, когда f:ajax отсутствует. На самом деле параметр передается кодом: method.invoke(context.getELContext(), новый объект[] {значение});

2. @boblemar передача параметров в backingbean через язык выражения возможна, но зависит от используемого вами сервера приложений. Я использую glassfish v3, и я могу это сделать. В любом случае, здесь, в этой ссылке, вы можете увидеть другие альтернативы для передачи этого значения: mkyong.com/jsf2 /…

3. ОК. Я не знал. В любом случае, я не думаю, что это было бы полезно в моем случае … и я нацелен на Tomcat6. Спасибо за ссылку.

Ответ №2:

ОК. Это решено… но мне это не очень нравится.
Вы подумаете, что я дурак: я решил проблему, удалив <![CDATA, окружающие мои скрипты!
Я уже обнаружил некоторые проблемы с использованием CDATA. Я не знаю, является ли это ошибкой MyFaces или что-то, что я делаю неправильно, например, помещаю много блоков h: outputScript с CDATA в составные компоненты, но с CDATA я получаю ошибки или не работаю. Просто удалив его, он работает!