JSF2: действие и действиеListener
Из этого ответа от BalusC здесь Различия между действием и actionListener, Use actionListener if you want have a hook before the real business action get executed, e.g. to log it, and/or to set an additional property (by <f:setPropertyActionListener>,
. Однако, когда я решаю написать какой-то код для проверки этого, результат немного отличается. Вот мой небольшой код
<h:form id="form">
<h:panelGroup id="mygroup">
<p:dataTable id="mytable" value="#{viewBean.foodList}" var="item">
<p:column>
#{item}
</p:column>
<p:column>
<p:commandButton value="delete"
action="#{viewBean.delete}"
update=":form:mygroup">
<f:setPropertyActionListener target="#{viewBean.selectedFood}"
value="#{item}"/>
</p:commandButton>
</p:column>
</p:dataTable>
</h:panelGroup>
</h:form>
Вот мой bean
@ManagedBean
@ViewScoped
public class ViewBean {
private List<String> foodList;
private String selectedFood;
@PostConstruct
public void init(){
foodList = new ArrayList<String>();
foodList.add("Pizza");
foodList.add("Pasta");
foodList.add("Hamburger");
}
public void delete(){
foodList.remove(selectedFood);
}
//setter, getter...
}
Согласно BalusC, actionListener
здесь более подходит, но в моем примере показано иначе.
Приведенный выше код отлично работает с action
, но если я переключусь на actionListener
, значит, он не работает. Мне потребуется два клика, чтобы удалить запись этой таблицы с помощью actionListener
, а если я использую action
, она удаляет запись каждый раз, когда я нажимаю кнопку. Интересно, может ли какой-нибудь эксперт JSF помочь мне понять action
vs actionListener
Примечание Если я переключусь на actionListener
, мой метод delete
станет public void delete(ActionEvent actionEvent)
Ответы
Ответ 1
Вы вводите в заблуждение action
с помощью actionListener
. actionListener
всегда работает перед action
. Если есть несколько прослушивателей действий, они запускаются в том же порядке, в каком они были зарегистрированы. Поэтому он не работает так, как ожидалось, когда вы используете actionListener
для вызова бизнес-действия и <f:setPropertyActionListener>
для установки (подготовки) свойства, которое должно использоваться бизнес-действием. Эта проблема была указана и исправлена в вашем предыдущем вопросе Является ли это ошибкой Primefaces или ошибкой Mojarra/MyFaces.
Независимо от того, что у вас есть в методе delete()
, очевидно, является бизнес-действием и вместо него следует использовать action
. Бизнес-действие обычно вызывает службу EJB, а при необходимости также устанавливает конечный результат и/или переходит к другому виду.
Ответ 2
Я попробовал ваш пример с оригинальными тегами JSF <h:commandButton>
, но я тоже получаю тот же симптом. Я считаю, что если вы укажете атрибут actionListener
и в то же время объявите другого слушателя с помощью <f:setPropertyActionListener>
, слушатель в атрибуте actionListener
будет запущен перед другим.
UPDATE. Я проверяю свое предположение следующим кодом:
-
Измените функцию delete
на следующую:
public void delete(){
this.selectedFood = "Chicken";
//foodList.remove(selectedFood);
}
-
Добавить <h:outputText id="food" value="#{viewBean.selectedFood}" />
внутри <h:panelGroup id="mygroup">
.
Вы увидите, что outputText всегда Chicken
.