0
votes

I just started learning JSF and PrimeFaces, and I'm having a hard time trying to get PrimeFaces' datatable to work. I have a checkbox-based selection mechanism (more than one row can be selected at the same time), so that clicking on the "Delete selected users" button triggers a method call to the backing bean to delete the corresponding users from the database.

The problem is that the selected rows are not stored in the backing bean's selectedUsers array, and I can't understand why, since my code is exactly the same as the one hosted on PrimeFaces' ShowCase. As a consequence, the button successfully triggers the confirmation dialog, but no user ever gets deleted from the system. Does anyone have any advice?

Thank you in advance!

xhtml file

<h:form id="tableForm">
    <p:dataTable id="userList" var="user" value="#{userListBean.userList}"
                 selection="#{userListBean.selectedUsers}" rowKey="#{user.username}">
        <f:facet name="header">User list</f:facet>

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

        <!-- data columns here, working just fine -->

        <f:facet name="footer">
            <p:commandButton value="Delete selected users" icon="ui-icon-trash" action="#{userListBean.deleteSelectedUsers()}">
                <p:confirm header="Deletion confirmation" message="Are you sure you want to delete #{fn:length(userListBean.selectedUsers)} users?" icon="ui-icon-alert" />                         
            </p:commandButton>
            Registered users: #{fn:length(userListBean.userList)}
        </f:facet>
    </p:dataTable>

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

Backing Bean (userMgr handles persistence on the server, it should have nothing to do with my issue)

@ManagedBean(name="userListBean")
@ViewScoped
public class UserListBean {
    @EJB
    private UserManager userMgr;
    private List<UserDTO> userList;
    private UserDTO[] selectedUsers;

    public UserListBean() {

    }

    public void deleteSelectedUsers() {
        for(UserDTO u : selectedUsers)
            userMgr.deleteUser(u.getUsername());

        setUserList(userMgr.retrieveAllUsersDTO());
    }

    public List<UserDTO> getUserList() {
        if(userList == null)
            setUserList(userMgr.retrieveAllUsersDTO());

        return userList;
    }

    public void setUserList(List<UserDTO> userList) {
        this.userList = userList;
    }

    public List<UserDTO> retrieveUserList() {
        return userMgr.retrieveAllUsersDTO();
    }

    public UserDTO[] getSelectedUsers() {
        return selectedUsers;
    }

    public void setSelectedUsers(UserDTO[] selectedUsers) {
        this.selectedUsers = selectedUsers;
    }

}

(As a side question: the #{fn:length(userListBean.selectedUsers)} EL expression always returns 0. I used to think it was because of the broken selection mechanism, but could it be because the array is still empty when the confirmation dialog is rendered?)

1
Not an answer : org.primefaces.model.LazyDataModel<T> should be preferable, in this case. A view scoped bean must implement the java.io.Serializable interface. - Tiny
First of all move all that logic in getUserList into a method annotated with @PostConstruct. Then your getUserList should do only what it says: gets userList - kolossus
Thank you all, guys, I didn't know about the @PostConstruct annotation! Still lots to learn. Everything works after correcting the getter like kolossus suggested, even if I don't get what it has to do with my issue... - thequanticlad

1 Answers

1
votes

You need to activate event rowSelect by adding <p:ajax event="rowSelect"/> to dataTable.