JSF/Primefaces Action Listener not invoked from p:commandButton

Michael Laris Source

I am migrating an JSP/Servlets website to JSF and am having difficulty in implementing some of the more interesting abilities of JSF. The current problem that I have attempted to resolve for several days is deleting one or more rows from a <p:dataTable>. The following code snippet defines the table:

<ui:composition template="/templates/RescueDBAdminTemplate.xhtml" ... > 
<ui:define name="body">
    <div id="mainContent">
        <h1> Pet Information Edit </h1>

        <p>
           This page allows the detailed information for an animal to be inserted or edited.
        </p>
        <br />

        <!--
        ~~~~ The first row contains the AIF number, and two optional hyperlinks to the History and Cage Card
        ~~~~ pages.  Since we have at most three entries, and a layout of 4 columns, we will need a sub-table
        ~~~~ to evenly space out these objects.
        ~~~~ -->
        <table class="w100pct">
           <tr>
              <!--
              ~~~~ Display the AIF_NO for the animal at the top of the page.  For Reference Only.
              ~~~~ -->
              <td class="label" align="left" >
                 AIF Number: #{animals.aifNo}
              </td>

              <td align="center"> <a href="/${context}/Protected/AifServlet?COMMAND=HISTORY&amp;AIF_NO=${aifBean.aifNo}" target="window"> Display History   </a> </td>
              <td align="right">  <a href="/${context}/Protected/AifServlet?COMMAND=CARD&amp;AIF_NO=${aifBean.aifNo}"    target="window"> Display Cage Card </a> </td>
           </tr>
        </table>

        <p:accordionPanel id="profile" multiple="true" activeIndex="0,1,2,3,4,5,6,7">
            <p:tab title="Cage Card Information">
                <h:form id="cageCardForm">
                    <p:panelGrid styleClass="rdbGrid w100pct">
                        <p:row>
                            <p:column styleClass="block"> Child Friendly: </p:column>
                            <p:column>
                                <p:selectOneMenu id="childFriendly" value="#{animals.isChildFriendly}">
                                    <f:selectItem itemValue="Y" itemLabel="Yes"     />
                                    <f:selectItem itemValue="N" itemLabel="No"      />
                                    <f:selectItem itemValue="U" itemLabel="Unknown" />
                                    <f:selectItem itemValue="O" itemLabel="Older Children Only" />
                                </p:selectOneMenu>
                            </p:column>
                            <p:column styleClass="block"> Dog Friendly:   </p:column>
                            <p:column>
                                <p:selectOneMenu id="dogFriendly" value="#{animals.isDogFriendly}">
                                    <f:selectItem itemValue="Y" itemLabel="Yes"       />
                                    <f:selectItem itemValue="N" itemLabel="No"        />
                                    <f:selectItem itemValue="U" itemLabel="Unknown"   />
                                    <f:selectItem itemValue="T" itemLabel="Tolerates" />
                                    <f:selectItem itemValue="S" itemLabel="Some"      />
                                </p:selectOneMenu>
                            </p:column>
                        </p:row>
                        <p:row>
                            <p:column styleClass="block"> Cat Friendly:   </p:column>
                            <p:column>
                                <p:selectOneMenu id="catFriendly" value="#{animals.isCatFriendly}">
                                    <f:selectItem itemValue="Y" itemLabel="Yes"       />
                                    <f:selectItem itemValue="N" itemLabel="No"        />
                                    <f:selectItem itemValue="U" itemLabel="Unknown"   />
                                    <f:selectItem itemValue="T" itemLabel="Tolerates" />
                                    <f:selectItem itemValue="S" itemLabel="Some"      />
                                </p:selectOneMenu>
                            </p:column>
                            <p:column styleClass="block"> Housebroken:    </p:column>
                            <p:column>
                                <p:selectOneMenu id="housebroken" value="#{animals.isHousebroken}">
                                    <f:selectItem itemValue="Y" itemLabel="Yes"       />
                                    <f:selectItem itemValue="N" itemLabel="No"        />
                                    <f:selectItem itemValue="U" itemLabel="Unknown"   />
                                </p:selectOneMenu>
                            </p:column>
                        </p:row>

                        <p:row>
                            <p:column styleClass="block" style="text-align:top;"> Cage Card Comments:  </p:column>
                            <p:column> <p:inputTextarea name="previousOwner" rows="11" cols="40" value="#{animals.cageCardComment}" /> </p:column>
                            <p:column styleClass="block" style="text-align:top;"> Lifestyle Needs:  </p:column>
                            <p:column> <p:inputTextarea name="reasonObtained" rows="11" cols="40" value="#{animals.lifestyleNeeds}" /> </p:column>
                        </p:row>
                    </p:panelGrid>
                </h:form>
            </p:tab>
            <p:tab title="Fees and Expenditures">
                <h:form id="feesForm">
                    <p:panelGrid styleClass="rdbGrid w100pct">
                       <p:row>
                           <p:column styleClass="block"> Adoption Fee:  </p:column>
                        <p:column>
                            <p:inputText size="16" value="#{animals.adoptionFee}" maxlength="64" />
                        </p:column>
                        <p:column styleClass="block"> Normal Costs:  </p:column>
                        <p:column>
                            <p:inputText size="16" value="#{animals.costRegular}" maxlength="64" />
                        </p:column>
                    </p:row>
                    <p:row>
                        <p:column styleClass="block"> Extra Costs:   </p:column>
                        <p:column>
                            <p:inputText size="16" value="${aifBean.costNonRegular}" maxlength="64" />
                        </p:column>
                        <p:column styleClass="block"> Extra Cost Description </p:column>
                        <p:column>
                            <p:inputTextarea rows="4" cols="40" value="#{animals.nonRegularDesc}" />
                        </p:column>
                    </p:row>
                    <p:row>
                        <p:column styleClass="block"> Comments </p:column>
                           <p:column colspan="3">
                                <p:inputTextarea rows="2" cols="80" value="#{animals.comments}" />
                        </p:column>
                    </p:row>
                    </p:panelGrid>
                </h:form>
            </p:tab>
            <p:tab title="Medical History">
                <p:dataTable styleClass="w100pct" var="current" value="#{medical.getMedHistoryByAifNo(param.AIF_NO)}">
                    <p:column headerText="Delete">
                        Delete
                    </p:column>

                    <p:column headerText="Procedure Name">
                        #{current.shortName}
                    </p:column>

                    <p:column headerText="Date">
                        #{current.treatmentDate}
                    </p:column>

                    <p:column headerText="Vet Information">
                        #{current.vetName} #{current.vetClinic}
                    </p:column>

                    <p:column headerText="Comments">
                        #{current.comments}
                    </p:column>
                </p:dataTable>
            </p:tab>   
            <p:tab title="Documents">
                <h:form id="docListForm">
                    <p:dataTable id="docListTable" styleClass="w100pct" var="current" value="#{documents.currentDocList}"
                                 paginator="true" rows="10" selection="#{documents.selectedDocs}">

                        <p:column selectionMode="multiple" style="width:2%" />  

                        <p:column headerText="Date">
                            <h:outputText value="#{current.treatmentDate}" />
                        </p:column>

                        <p:column headerText="Document Type">
                            <h:outputText value="#{current.group}" converter="com.rescuedb.DocGroupName" />
                        </p:column>

                        <p:column headerText="Description">
                            #{current.description}
                        </p:column>

                        <f:facet name="footer">  
                            <p:commandButton id="docListDelete" value="Delete Selected Records" 
                                             icon="ui-icon-search" 
                                             update=":#{p:component('docListTable')}" 
                                             actionListener="#{documents.deleteReference}" >
                                <f:param name="docNo" value="#{current.docNo}" />
                                <f:param name="refNo" value="#{animals.aifNo}" />
                                <f:param name="group" value="#{current.group}" />
                            </p:commandButton>  
                        </f:facet>
                    </p:dataTable>
                </h:form>
            </p:tab>
        </p:accordionPanel>

    </div>
</ui:define>
</ui:composition>

The managed bean that backs this page is as follows (this is fairly preliminary code, as I am still experimenting with PrimeFaces and JSF):

package com.rescuedb.beans.managed;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.apache.log4j.Logger;

import com.rescuedb.Beans.DocMasterBean;
import com.rescuedb.Beans.DAO.DocMaster;
import com.rescuedb.Beans.DAO.DocXref;
import com.rescuedb.Beans.Models.DocMasterDataModel;
import com.rescuedb.Core.RescueException;

@ManagedBean(name="documents")
@ViewScoped
public class DocumentManagedBean implements Serializable
{

    static final long serialVersionUID = 5L;

    static Logger logger = Logger.getLogger(DocumentManagedBean.class);

    private transient DocMaster             docInfo;            // Document Master accessor object
    private transient DocXref               xrfInfo;            // Document Master accessor object

    private String  currentAifNo;
    private String  refNo;
    private String  docNo;

    /**
     * Contains a list of document records, wrapped in a DataModel, for the currently 
     * active foster animal.
     */
    private DocMasterDataModel currentDocList = null;           

    private DocMasterBean[] selectedDocs;

    public DocumentManagedBean()
    {
        logger.trace ("DocumentManagedBean.constructor");
        try {
            //
            // Retrieve the URL parameter from the context.
            //
            FacesContext       context    = FacesContext.getCurrentInstance();
            Map<String,String> paramMap   = context.getExternalContext().getRequestParameterMap();
            String             paramAifNo = paramMap.get("AIF_NO");

            if (paramAifNo != null) {
                if (!paramAifNo.isEmpty()) {
                    currentAifNo = paramAifNo;
                    loadCurrentDocList();
                }
            }
        } catch (Exception e) {
            logger.error ("Exception caught in DocumentManagedBean() constructor :: " + e.getMessage(), e);
        }
    }

    /**
     * Initialize the bean from the database.   
     */
    @PostConstruct
    public void initialize ()
    {
        logger.trace ("DocumentManagedBean.initialize");
        try {
            docInfo = new DocMaster();
            xrfInfo = new DocXref();
        } catch (Exception e) {
            logger.error ("Exception in DocumentsManagedBean.initialize() : " + e.getMessage(), e);
        }
    }

    public List<DocMasterBean> getDocList()
    {
        logger.trace ("DocumentManagedBean.getDocList");
        return docInfo.getRecordList();
    }

    /**
     * Retrieve the list of documents that are associated wit a specific foster animal.
     * <p>
     * @param aifNo
     * @return
     */
    public DocMasterDataModel getCurrentDocList()
    {
        logger.trace ("DocumentManagedBean.getCurrentDocList");
        return currentDocList;
    }

    /**
     * Load the document list for the currently active foster animal.
     */
    private void loadCurrentDocList()
    {
        DocMaster docMaster = null;

        logger.info ("DocumentManagedBean.loadCurrentDocList");
        try {
            docMaster = new DocMaster();
            if (currentAifNo != null) {
                if (!currentAifNo.isEmpty()) {
                    docMaster.queryByRefNo (Integer.parseInt(currentAifNo));
                    currentDocList = new DocMasterDataModel (docMaster.getRecordList());
                    logger.info ("DocumentManagedBean.loadCurrentDocList :: currentDocList reloaded, length = " + docMaster.getRecordCount());
                } else {
                    logger.info ("DocumentManagedBean.loadCurrentDocList :: currentAifNo is empty, no records loaded.");
                }
            } else {
                logger.info ("DocumentManagedBean.loadCurrentDocList :: currentAifNo is null, no records loaded.");
            }
        } catch (Exception e) {
            logger.error ("Exception in DocumentsManagedBean.loadCurrentDocList() : " + e.getMessage(), e);
        }
    }

    public void deleteReference(ActionEvent event)
    {
        boolean        status;                // Status of the update.
        int            refNo = 0;
        int            docNo = 0;

        logger.info ("DocumentManagedBean.deleteReference");
        try {
            //
            // Retrieve the parameter of the request.
            //
            FacesContext       context    = FacesContext.getCurrentInstance();
            Map<String,String> paramMap   = context.getExternalContext().getRequestParameterMap();
            String             paramDocNo = paramMap.get("docNo");
            String             paramRefNo = paramMap.get("refNo");
            logger.info (String.format("DocumentManagedBean.deleteReference :: paramDocNo = [%s]", paramDocNo));
            logger.info (String.format("DocumentManagedBean.deleteReference :: paramRefNo = [%s]", paramRefNo));

            //
            // Retrieve the items necessary to delete the proper records.
            // The refNo parameter will only be specified when a specific cross-referenced
            // record is to be deleted.  If this value is missing, then the master document
            // is to be deleted.
            //
            if (paramRefNo != null) {
                try {
                    refNo = Integer.parseInt (paramRefNo);
                    this.refNo = paramRefNo;
                } catch (NumberFormatException e) {
                    refNo = 0;
                }
            }

            //
            // The docNo has to be present.  If the refNo is zero, then we will delete the
            // master document.  If a refNo is present, then we will delete a cross reference.
            //
            if (paramDocNo != null) {
                try {
                    docNo = Integer.parseInt (paramDocNo);
                    this.docNo = paramDocNo;
                } catch (NumberFormatException e) {
                    docNo = 0;
                    String message = String.format ("Illegal value for docNo (%d)", docNo);
                    logger.error(String.format("DocumentManagedBean.deleteReference :: Exception Message [%s]", message));
                    throw new RescueException ("DS000091", message, "DocumentsManagedBean", "deleteReference");
                }
            } else {
                logger.error("DocumentManagedBean.deleteReference :: paramDocNo is null");
            }

            //
            // Delete the cross reference record.
            //
            if (refNo != 0) {
                xrfInfo = new DocXref();
                status  = xrfInfo.queryByCrossRef (docNo, refNo);
                if (status != true) {
                    String message = String.format ("Error querying DOC_xref for refNo = %d, docNo = %d", refNo, docNo);
                    logger.error(String.format("DocumentManagedBean.deleteReference :: Exception Message [%s]", message));
                    throw new RescueException ("DS000092", message, "DocumentsManagedBean", "deleteReference");
                } else {
                    status = xrfInfo.delete();
                    logger.warn("DocumentManagedBean.deleteReference :: Document XRef deleted");
                    // logger.warn("DocumentManagedBean.deleteReference :: TEST TEST TEST Document XRef not actually deleted");
                    if (status != true) {
                        String message = String.format ("Error deleting DOC_xref for refNo = %d, docNo = %d", refNo, docNo);
                        logger.error(String.format("DocumentManagedBean.deleteReference :: Exception Message [%s]", message));
                        throw new RescueException ("DS000093", message, "DocumentsManagedBean", "deleteReference");
                    } else {
                        loadCurrentDocList();
                        logger.error("DocumentManagedBean.deleteReference :: currentDocList reloaded");
                    }
                }
            } else {
                logger.error("DocumentManagedBean.deleteReference :: refNo is 0.  No Records were deleted.");
            }
        } catch (RescueException e) {
            logger.error ("RescueException in DocumentsManagedBean.deleteReference() :: " + e.getMessage(), e);
        } catch (Exception e) {
            logger.error ("Exception in DocumentsManagedBean.deleteReference()", e);
        }
    }

    public DocMaster getDocInfo() 
    {
        logger.info ("DocumentManagedBean.getDocInfo");
        return docInfo;
    }

    public void setDocInfo(DocMaster docInfo) 
    {
        logger.info ("DocumentManagedBean.setDocInfo");
        this.docInfo = docInfo;
    }

    public String getRefNo() 
    {
        logger.info ("DocumentManagedBean.getRefNo");
        return refNo;
    }

    public void setRefNo(String refNo) 
    {
        logger.info ("DocumentManagedBean.setRefNo");
        this.refNo = refNo;
    }

    public String getDocNo()
    {
        logger.info ("DocumentManagedBean.getDocNo");
        return docNo;
    }

    public void setDocNo(String docNo) 
    {
        logger.info ("DocumentManagedBean.setDocNo");
        this.docNo = docNo;
    }

    public DocMasterBean[] getSelectedDocs() 
    {  
        logger.info ("DocumentManagedBean.getSelectedDocs");
        return selectedDocs;  
    }  

    public void setSelectedDocs(DocMasterBean[] selectedDocs) 
    {  
        logger.info ("DocumentManagedBean.setSelectedDocs");
        this.selectedDocs = selectedDocs;  
    }  
}

I have tried a number of different strategies, and have read a fair number of very detailed explanations of this process in other StackOverflow threads (Thank you, BalusC!), but have still been unable to actually invoke the action listener.

My Environment is as follows:

  • Java 1.6
  • Eclipse Kepler (originally Juno)
  • GlassFish 3.1.2
  • PrimeFaces 3.5.0

From a presentation perspective, the XHTML displays correctly. The <p:dataTable> element is rendered just like the documentation and examples indicate, but when I attempt to delete a a row, the listener is never invoked.

I have tried changing the update name several times. Currently, the value of the update parameter is profile:docListForm:docListTable.

Other posts seem to indicate that there was a problem with <p:commandButton> from within a <p:accordianPanel>, but that was for a previous version of PrimeFaces (3.2).

I have tried moving the <p:commandButton> outside the <p:dataTable> and also on each row, yet the behavior does not change.

ajaxjsfprimefaces

Answers

answered 5 years ago Subodh Joshi #1

Try to add ajax="false" attribute in commandbutton ,Something like this.

<p:commandButton value="Non-Ajax Submit" actionListener="#{pprBean.savePerson}"   
        ajax="false" />  

Or use h:commandButton with ajax="false" here also . In my application i got same issue plenty of time and i got answer few week back that issue with the page or code somewhere in the page or managed bean throwing exception or some logic going fail which is generating exception for JSF that is the main reason behind firing the event.It is JSF2 feature not to fire event if code or logic fail somewhere . May be this will help you

answered 5 years ago TDupard #2

If your Listener does not trigger try this, it work fine in p:tables

<p:column id="delete" headerText="Action"  width="65"> 
    <h:commandLink value="Delete" 
    action="#{documents.deleteReference(current.docNo,animals.aifNo,current.group)}"   ajax="false" />
</p:column>

And in your documents bean:

public void deleteReference(String docNo, String aifNo, String group)

You can actually pass the 2 string that you eventually cast as int but as Integer wrapper in the method not the primitive.

Cheers,

Thierry

comments powered by Disqus