0

If I have a dataTable which is controlled by a requestScoped named bean, the named bean(backing bean) query data from EJB and EJB query data via entityManager and JPA.

For the view part, I use the dataTable from PrimeFaces: My question is: If I open two tab in one browser or two(problem is same): I delete one row in one tab and then go to another tab which is not refreshed(so the deleted row is still there). If I press delete commandLink again, the delete row will of course be deleted because the page is refreshed but the problem is that it also deletes the row right below it. By the way, my JSF version is 2.2 and primefaces is 4.0(now I replace it with 8.0 and the error persists). Is it a jsf or primefaces bug(I never try the h:commandLink and h:dataTable) or some mistake I made?

You can reference below code for named bean:

    @Named(value="allIndustryController")
    @RequestScoped
    public class AllIndustryController {
    
    @Inject
    IndustryTypeBean industryTypeBean;
    
    private List<Industry> industries;
    
    public AllIndustryController() {
        
        
    }
    
    @PostConstruct
    public void init() {
        industries = industryTypeBean.getAllIndustrys();
    }


    public List<Industry> getIndustries() {
        
        return industries;
    }

    public void setIndustries(List<Industry> industries) {
        this.industries = industries;
    }
    
    public String deleteIndustry(int industryID) {
        
        try {
            
            boolean result = industryTypeBean.removeIndustry(industryID);
            if (result) {
                init();
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Industry " + industryID +" has been deleted succesfully"));
            }
        }catch(Exception ex){
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Delete Industry Failed"));
        }
        return "allIndustries.xhtml?faces-redirect=true";
        
    }
    
    public void updateIndustry(int industryID, String industryName) {
        Industry industry = industryTypeBean.findIndustryByID(industryID);
        industry.setIndustryName(industryName);
        industryTypeBean.editIndustry(industry);
        
    }
    
    public String addIndustry() {
        Industry industry = new Industry();
        industryTypeBean.addIndustry(industry);
        return "allIndustries.xhtml?faces-redirect=true";
        
    }

}

The code for dataTable:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui">

<h:head>
    <title>All Industries</title>
    <h:outputStylesheet library="css" name="bootstrap.min.css"></h:outputStylesheet>
</h:head>
<body>
    <div class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="navbar-brand">Customer Management System</div>

        <div class="collapse navbar-collapse">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item active"><h:link class="nav-link"
                        value="Home | " outcome="index.xhtml" /></li>
                <li class="nav-item"><h:link class="nav-link"
                        value="Manage All Users | " outcome="allUsers.xhtml" /></li>
                <li class="nav-item"><h:link class="nav-link"
                        value="Manage All Customers |" outcome="allCustomers.xhtml" /></li>
                <li class="nav-item"><h:link class="nav-link"
                        value="Manage Industries |" outcome="allIndustries.xhtml" /></li>
                <h:form>
                    <li class="nav-item"><h:commandLink class="nav-link"
                            value="Log out" action="#{loginController.logout()}" /></li>
                </h:form>
            </ul>
        </div>
    </div>

    <h:form id="MyForm">
        <p:dataTable class="table table-bordered table-striped"
            id="myIndustryList" value="#{allIndustryController.industries}"
            var="industry">
            <p:column headerText="industryID">
                <p:outputLabel value="#{industry.industryID}" id="industryID" />
            </p:column>
            <p:column headerText="industryName">
                <p:inputText value="#{industry.industryName}" id="industryName" />
            </p:column>


            <p:column headerText="Operations">
                <p:commandLink value="Delete | " ajax="true"
                    action="#{allIndustryController.deleteIndustry(industry.industryID)}"
                    disabled="#{industry.industryID == null}" update="myIndustryList">
                    <p:confirm header="Confirmation" message="Are you sure?"
                        icon="pi pi-exclamation-triangle" />
                </p:commandLink>

                <p:commandButton value="update Name"
                    action="#{allIndustryController.updateIndustry(industry.industryID,industry.industryName)}"
                    oncomplete="PF('cd').show()">
                    <!-- <f:param name="userAccount" value="#{normalUser.account}" /> -->
                </p:commandButton>

            </p:column>

            <!--                            <h:link value="View | " outcome="userDetail.xhtml">
                                pass the parameter to next page, the param name is propertyID, and the value is index + 1.
                                You can get the value from next page using the indexController
                                <f:param name="userAccount" value="#{normalUser.account}" />
                                
                            </h:link> 
                            
                            <h:link value="Edit | " outcome="editUser.xhtml">
                                pass the parameter to next page, the param name is propertyID, and the value is index + 1.
                                You can get the value from next page using the indexController
                                <f:param name="userAccount" value="#{normalUser.account}" />
                            </h:link>  -->


            <!-- reference:https://stackoverflow.com/questions/19362983/how-to-add-confirmation-dialog ; https://www.primefaces.org/showcase/ui/data/datatable/basic.xhtml-->


        </p:dataTable>

        <p:confirmDialog global="true" showEffect="fade" hideEffect="fade">
            <p:commandButton value="Yes" type="button"
                styleClass="ui-confirmdialog-yes" icon="pi pi-check" />
            <p:commandButton value="No" type="button"
                styleClass="ui-confirmdialog-no" icon="pi pi-times" />
        </p:confirmDialog>
        <h:outputText value=" " />

        <p:dialog header="Save the name" severity="alert" widgetVar="cd">
            <h:outputText value="The Industry Name is saved" />
        </p:dialog>

        <div>
            <h:commandButton id="add" value="Add"
                action="#{allIndustryController.addIndustry()}"
                class="btn btn-primary" />

            <h:commandButton id="viewAll" value="View All"
                action="allIndustries.xhtml?faces-redirect=true"
                class="btn btn-primary">
            </h:commandButton>
        </div>

        <!--            <div>
                <h:inputText value="#{adminApplication.searchedAccount}"
                    id="searchByAccount"
                    onchange="if (document.getElementById('MyForm:searchByAccount').value.trim() == '') {document.getElementById('MyForm:searchByAccount').value = '';} " />
                <h:commandButton id="search" value="Search by Account"
                    action="#{adminApplication.searchUserByAccount(adminApplication.searchedAccount)}"
                    class="btn btn-primary">
                </h:commandButton>
            </div> -->
    </h:form>



</body>
</html>
  

------------------------------Update-------------------------------

Actually I solve this problem by using <f:param> to check againt the one passed by named bean's method. I forgot the update it due to the heavy assignments. (Sorry Moreover, If I use some search feature on the page(I filter the ArrayList which stores the industry), the delete action can neither be performed on the correct the row:

I guess I can summarize the problem as below: Whenever I update the actual dataTable's data source in backing bean, I cannot pass parameter(the parameter will not be consistent and it seems to be a index problem? just a wild guess) inside a method of backing bean. Anyway, f:param can alway give the right one

For more people who are interested, I post the IndustryType.java code though it is not related to the problem. The problem is still about how the primefaces process the xhtml files. Welcome to more detailed explanation and hope this post can be useful to more people :

package beans;

import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

import entity.Industry;
import repository.IndustryRepository;

@Named
@SessionScoped
public class IndustryTypeBean implements Serializable {
    
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @EJB
    IndustryRepository industryRepository;
    
    public List<Industry> getAllIndustrys(){
        try {
        List<Industry> industrys = industryRepository.getAllIndustries();
        return industrys;
        }catch (Exception ex) {
            Logger.getLogger(IndustryTypeBean.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    
    public boolean addIndustry(Industry Industry) {
        try {
            industryRepository.addIndustry(Industry);
            return true;
        }catch(Exception ex) {
            Logger.getLogger(IndustryTypeBean.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
        
    }
    
    public boolean removeIndustry(int industryID) {
        try {
            industryRepository.deleteIndustry(industryID);
            return true;
        } catch(Exception ex) {
            Logger.getLogger(IndustryTypeBean.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
        
    }
    
    public boolean editIndustry(Industry Industry) {
        try {
            industryRepository.updateIndustry(Industry);
            return true;
        }catch(Exception ex) {
            Logger.getLogger(IndustryTypeBean.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
        
    }
    
    public Industry findIndustryByID (int industryID) {
        try {
            
            return industryRepository.findIndustryByID(industryID);
        }catch(Exception ex) {
            Logger.getLogger(IndustryTypeBean.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;    
    }
    

}

In JSF, there is CDI for viewscope and flowscope so that you have to use other implementation. textbook quote

Stan
  • 602
  • 6
  • 23
  • 1
    PrimeFaces 4.0 is VERY old so there is a chance its a bug that has been fixed in the 6 years since PF 4.0 was released. PF is up to 8.0 by the way. – Melloware Oct 01 '20 at 18:16
  • Thanks. But for JSF 2.2, I guess prime faces 4.0 it is better? Any suggestion for primefaces version for JSF 2.2? @Melloware – Stan Oct 02 '20 at 07:17
  • 1
    PF 8 is compatible with JSF 2.2, see https://github.com/primefaces/primefaces – Jasper de Vries Oct 02 '20 at 11:43
  • Actually, I have tried version 8 and the bug is still there. I have to pass to double check the value. – Stan Oct 02 '20 at 17:32
  • Debugging your code do you get differents value for industryID, clicking the same button on the two tabs? Can you post the code of IndustryTypeBean class? – WoAiNii Oct 02 '20 at 20:39
  • @WoAiNii, yes I have debugged: the id passed by f:param and the one passed through the managedBean method is indeed different. I think it is a innate bug though I have upgrade it to version 8(newest one) – Stan Oct 06 '20 at 06:27
  • @StanPeng good things only come to people who wait :) – Sabito stands with Ukraine Oct 29 '20 at 13:22
  • @BalusC, I think session scope is fine when loading data from database. I will try viewscope but I remember it not allowed to use.(only omnifaces). The duplicate link answer is actually that related to my question because I don't have problem with using h:dataTable(i have other table using it and it works fine). It is more like a problem with primefaces – Stan Oct 30 '20 at 00:54

0 Answers0