1
votes

I have a datatable that is initially populated with no data (an empty list). There is a commandButton in the footer of the table that adds rows to the table. When a row is added, the last cell in the row is another commandButton to delete the row. My issue is that the delete button keeps deleting the first row in the table regardless of which row is selected.

Example: if I add 3 rows to the table and hit the delete button in the last cell of the second row, action="#{addAccountBean.deleteFixVendor(dataItem)}" passes the first row to the deleteFixVendor method instead of the second row which was clicked. I can't figure out why the object for the first row keeps on getting passed to the delete method regardless of which row button is clicked.

My JSF code:

<h:form>
<f:validateBean disabled="#{!empty param['disableValidation']}" >
<p:panel id="panel" header="Add New Account"  > 
    <p:dataTable var="dataItem" value="#{addAccountBean.account.vendors}" >

        <p:column headerText="Vendor"  >                                
            <p:selectOneMenu value="#{dataItem.vendor}">                
                        <f:selectItems value="#{addAccountBean.menu.fixOption}" />
                    </p:selectOneMenu>
            </p:column>

            <p:column headerText="Monthly Cost"  >
                <p:inputText value="#{dataItem.cost}" />    
            </p:column>

            <p:column headerText="Cost Date"  >
                <p:calendar value="#{dataItem.CDate}" pattern="MM/dd/yyyy" navigator="true" /> 
            </p:column>

            <p:column headerText="Delete" >
            <h:commandButton value="Delete" action="#{addAccountBean.deleteFixVendor(dataItem)}" >
                <f:param name="disableValidation" value="true" />
            </h:commandButton>  
        </p:column> 

        <f:facet name="footer" >
            <h:commandButton value="Add New Vendor" action="#{addAccountBean.addFixVendor}" >
                <f:param name="disableValidation" value="true" />
            </h:commandButton>      
        </f:facet>

    </p:dataTable>          
</p:panel>  
</f:validateBean>
</h:form>

Bean code:

@ManagedBean
@SessionScoped
public class AddAccountBean implements Serializable {

private AccountData account = new AccountData();

public String addFixVendor() {

    account.getVendors().add(new VendorData());                 
    return "";
}

public String deleteFixVendor(VendorData vData) {

    account.getVendors().remove(vData);                         
    return "";                                                          
}

Any suggestions are appreciated.

1
Did you conclude it based on observing or debugging? Did you put a breakpoint on deleteFixVendor() method and inspect the passed-in vData instance? Or was you merely observing the end result and assumed that the passed-in vData instance "would" be the first row? It's namely more likely that this problem is caused by a broken equals() method in VendorData class than by JSF/EL itself. - BalusC
Thank you @BalusC. It was a result of a broken equals() method in the VendorData class. It is now working. - Stevenyc091
okay. I posted an answer. - BalusC

1 Answers

1
votes

The code posted so far looks fine. The only feasible explanation for this problem is a broken equals() method in the VendorData class. The Collection#remove() will remove the first item in the collection which equals() the given object.

Provided that your (base) entity has an id property, then this should do:

@Override
public boolean equals(Object other) {
    return (other != null && getClass() == other.getClass() && id != null)
        ? id.equals(((VendorData) other).id)
        : (other == this);
}

@Override
public int hashCode() {
    return (id != null) 
        ? (getClass().hashCode() + id.hashCode())
        : super.hashCode();
}