From this answer by BalusC here Differences between action and 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>,
. However when I decide to write some code to test this, the result is a bit different. Here is my small code
<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>
Here is my 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...
}
According to BalusC, actionListener
is more suitable here, but my example show otherwise.
The above code work great with action
, but if I switch over to actionListener
, then it does not quite work. It will take two clicks for me to delete an entry of this table using actionListener
, while if I use action
, it delete entry every time I click the button. I wonder if any JSF expert out there can help me understand action
vs actionListener
Note If I switch to actionListener
, my delete
method become public void delete(ActionEvent actionEvent)
I tried your example with original JSF's tags
<h:commandButton>
but I also get the same symptom. I believe if you specifyactionListener
attribute and at the same time, declare another listener with<f:setPropertyActionListener>
, the listener in the attributeactionListener
will be fired before the other.UPDATE: I test my assumption with the following code:
Change your
delete
function to this one:Add
<h:outputText id="food" value="#{viewBean.selectedFood}" />
inside<h:panelGroup id="mygroup">
.You will see that the outputText is always
Chicken
.You're confusing
action
withactionListener
. TheactionListener
runs always before theaction
. If there are multiple action listeners, then they run in the same order as they have been registered. That's why it doesn't work as expected when you useactionListener
to call the business action and<f:setPropertyActionListener>
to set (prepare) a property which is to be used by the business action. This problem was pointed out and fixed in your previous question Is this Primefaces bug or Mojarra/MyFaces bug.Whatever you have in the
delete()
method is clearly a business action and should be invoked byaction
instead. A business action typically invokes an EJB service and if necessary also sets the final result and/or navigates to a different view.