JSF2: action and actionListener
Solution 1
You're confusing action
with actionListener
. The actionListener
runs always before the action
. 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 use actionListener
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 by action
instead. A business action typically invokes an EJB service and if necessary also sets the final result and/or navigates to a different view.
Solution 2
I tried your example with original JSF's tags <h:commandButton>
but I also get the same symptom. I believe if you specify actionListener
attribute and at the same time, declare another listener with <f:setPropertyActionListener>
, the listener in the attribute actionListener
will be fired before the other.
UPDATE: I test my assumption with the following code:
-
Change your
delete
function to this one:public void delete(){ this.selectedFood = "Chicken"; //foodList.remove(selectedFood); }
Add
<h:outputText id="food" value="#{viewBean.selectedFood}" />
inside<h:panelGroup id="mygroup">
.
You will see that the outputText is always Chicken
.
Thang Pham
Updated on January 01, 2020Comments
-
Thang Pham over 4 years
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 toactionListener
, then it does not quite work. It will take two clicks for me to delete an entry of this table usingactionListener
, while if I useaction
, it delete entry every time I click the button. I wonder if any JSF expert out there can help me understandaction
vsactionListener
Note If I switch to
actionListener
, mydelete
method becomepublic void delete(ActionEvent actionEvent)