JSF2: action and actionListener

2020-07-24 04:40发布

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)

2条回答
Animai°情兽
2楼-- · 2020-07-24 05:09

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.

查看更多
够拽才男人
3楼-- · 2020-07-24 05:20

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.

查看更多
登录 后发表回答