2

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.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Michael Laris
  • 21
  • 1
  • 5
  • In your action listener are you getting any output but your form is not being updated or is it not being called at all ? – Andy Jun 30 '13 at 23:09
  • I am not getting any output. I added the log message as the first executable line, and it is never getting to the output file, yet other log messages from the same class do appear in the log. – Michael Laris Jul 01 '13 at 00:40
  • Hmmm...ok. I'll try my best. – Andy Jul 01 '13 at 00:42
  • When you click on the button, you don't get any errors from Glassfish output window ? Like nothing ? – Andy Jul 01 '13 at 00:50
  • On clicking a button, it appears attempt to redraw the whole page. At least, I am getting an exception from a method in the bean that initializes a different section of the page. I do not think that the page is actually being redrawn, since from the user's perspective, nothing changes: No flicker, no pawse. – Michael Laris Jul 01 '13 at 12:33
  • The exception might be causing a halt to the JSF lifecycle process. That could be why you're not seeing a flicker. What does the exception say? A lot of this code is also too servlet "ish". Since I don't have the code I can't completly picture what you are trying to do. In your page you are going to have one button as the footer right ? When the user selects a row, you want them to hit delete button. I'm trying to build a smaller sample based on the xhtml portion you posted so that I can reproduce the error on my end. – Andy Jul 01 '13 at 22:08
  • Also, try to see if you are not running under any of the scenarios described by BalusC in this post http://stackoverflow.com/questions/2118656/hcommandlink-hcommandbutton-is-not-being-invoked I noticed you were calling a template, so hopefully the page portion was not being loaded inside of a second form. I'm just throwing things out there sorry. It might be just a simple as the answer given below but I'll know more I guess once I am able to build the sample. – Andy Jul 01 '13 at 22:13
  • One more thing, in your `setSelectedDocs(DocMasterBean[] selectedDocs)` add a print statement, select a few items and hit delete. Are you seeing anything in the server output window ? – Andy Jul 01 '13 at 23:37
  • I have tried several display scenarios, and yes, this one does have a button at the bottom. The idea here was that the user could select one or more checkboxes and then hit a single Delete button. It's not really surprising that the code is servlet-ish, since that was how it was originally written. Remember, this is prototype code. As for the exception, at this point I am logging and ignoring, so there is really no indication of an exception further up the call chain. I'll try the suggestions and post the results. – Michael Laris Jul 02 '13 at 23:48
  • I understand. The reason why I am asking if your selections are being set is because I was going over the docs for primeface's dataTable and it seems you're missing `rowKey` when you want multiple selections. Well there's more to it than just setting that attribute. – Andy Jul 03 '13 at 00:23
  • Oh and also, I did build a small sample base on the xhtml provided and I did notice that the values were not being set correctly (actuall they were not being set at all). Unless I am missing something, that's also another thing you need to account for. – Andy Jul 03 '13 at 01:08
  • Well, I read the post you suggested. Very interesting and it did point out two mistakes (one stupid, and one inadvertent), both of which I corrected, but still no joy. The listener is still not called. I'll check out the `rowKey` attribute. – Michael Laris Jul 03 '13 at 01:11
  • Before you do check the setter first. No need to chase something if you're not sure it's not there. – Andy Jul 03 '13 at 01:14
  • I did some experiments that yielded strange results. First, I removed all JSF markup from the XHTML page except the `` element that is attempting to use AJAX. And it worked. Hurrah! I then added back the `` and the enclosing '`, expecting it not to work, but was surprised when it did. I then started adding back other `` sections, eventually finding a section that when included prevented the actionListener from being invoked. But I see nothing wrong with the code or XHTML. – Michael Laris Jul 04 '13 at 16:38
  • I'm not sure I'm just an up and comer myself. Maybe your id is wrong. Simple test to check would be to update '@all' or '@form' instead of a particular id like you are doing. – Andy Jul 04 '13 at 16:47
  • Ok, I've been testing scenarios all day, and have found at least a partial answer. I needed to wrap all the input elements in `` elements, and not just the `` I was experimenting with. Since it was prototype code, I took a few shortcuts when writing the xhtml page, and was more interested in the general layout and the Ajax, which I am fairly inexperienced with. Not such a good idea, apparently. The `actionListener` gets invoked, and the row in the database is properly deleted, but the `` does not get redrawn. Any ideas? – Michael Laris Jul 05 '13 at 00:12
  • Weird cuz I built a sample based on your current code and I was not gettibg this. Maybe I changed it without realizing. Can you repost your code? Little edit on the bottom of your answer. I would have to see :/ – Andy Jul 05 '13 at 04:50
  • I have reposted my code (both the XHTML and the managed bean). Annoyingly, the `actionListener` is not getting called again, yet it was yesterday. There is something funky going on, and the solution will probably be trivial. – Michael Laris Jul 06 '13 at 16:29
  • Sorry. Just got back. I'll have a look. – Andy Jul 06 '13 at 23:53
  • If I do NOT select any of the checkboxes, and press the Delete button, the `actionListener` does get called. Of course, there is no data for the code work on, so the method fails and retuern a null, which causes the xhtml to successfully update the page. If I select one of the checkboxes, the `actionListener` does NOT get called. Why? – Michael Laris Jul 07 '13 at 18:51
  • I'm sorry Michael. I have no internet bad weather. I haven't had a chance to look at it. As soon as I'm able to I'll let you know. Ill keep an eye out for that – Andy Jul 07 '13 at 23:22
  • Last night I downloaded the Prime Faces ShowCase WAR file and installed it (and associated source code and library JAR's) on my system. It worked fine. When I replaced the `primefaces-3.5.jar` file with the version that came with the ShowCase WAR, I got different results (unable to select check boxes, actionListener still not invoked). I will attempt the reverse test case tonight, and see what happens. – Michael Laris Jul 09 '13 at 12:03
  • That's...weird...Let me see what I can find out with the new code you provided. – Andy Jul 09 '13 at 18:17

2 Answers2

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

TDupard
  • 43
  • 7
  • I have thought about this, and actually prototyped out something quite similar, but I really want to know why the Ajax code is not working when it should. Getting the Ajax updates working is important at this stage, since what I am doing now will become the prototype code for the rest of the project. I am going to go back to basics. My current plan is to download the source code for the PrimeFaces ShowCase example app. I'll install it on my system and see if it works. The `commandLink` method is going to be my fall-back plan. – Michael Laris Jul 08 '13 at 12:27
-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

Subodh Joshi
  • 12,717
  • 29
  • 108
  • 202
  • I tried this, which resulted in a much different response, but the listener was still not called. I have more investigation to do on this, though. – Michael Laris Jul 03 '13 at 01:13