vizzdoom
vizzdoom

Reputation: 736

Primefaces DataTable inline editing - can't update model without reloading the page

I am trying to implement table with users' accounts, which can be modified by administrators. I use primefaces (2.2) DataTable component with cellEditor.

I have onRowEditListener which uses manageUsers.onEditRow() method to persist changes in database via UserDAO object.

After loading the page and updating table cell - data in database change properly. Unfortunately, when I am trying to update previous row again - (UserDAO)event.getObject(); returns old object (the one after first change) and data are not updated.

When I reload page (F5) and edit row - then data are changed properly.

How can I update table or how can I get the freshest version of user without reloading page?

Using Primefaces 2.2, JSF 2.1, Glassfish 3.1

PAGE:

                <p:column headerText="login" filterBy="#{u.user.login}" filterMatchMode="contains" style="width:150px">  
                    <p:cellEditor>  
                        <f:facet name="output">  
                            <h:outputText value="#{u.user.login}" />
                        </f:facet>  
                        <f:facet name="input">  
                            <h:form>
                                <p:inputText value="#{u.user.login}" />  
                            </h:form>
                        </f:facet>  
                    </p:cellEditor>  
                </p:column>  

                <p:column headerText="email" filterBy="#{u.user.email}" filterMatchMode="contains" style="width:150px">  
                    <p:cellEditor>  
                        <f:facet name="output">  
                            <h:outputText value="#{u.user.email}" />  
                        </f:facet>  
                        <f:facet name="input">  
                            <h:form>
                                <p:inputText  value="#{u.user.email}" />  
                            </h:form>
                        </f:facet>  
                    </p:cellEditor>  
                </p:column> 

                //... other fields


                <p:column headerText="Options">  
                    <p:rowEditor />  
                </p:column>  

            </p:dataTable>  

        </h:form>

ManageBean with ApplicationScope (CDI)

@Named
@ApplicationScoped
public class ManageUsers implements Serializable {

    @Inject
    /** Inject database */
    private DB db;
    /** List with all leaked data which is loaded from database */
    private List<UserDAO> users;
    private User selectedUser;
    private SelectItem[] manufacturerOptions;

    public ManageUsers() {
        manufacturerOptions = createFilterOptions();
    }

    public SelectItem[] getManufacturerOptions() {
        return manufacturerOptions;
    }

    public User getSelectedUser() {
        return selectedUser;
    }

    public void setSelectedUser(User selectedUser) {
        this.selectedUser = selectedUser;
    }

    /** List of users loaded from database */
    public void getDataFromDatabase() {
        try {
            users = db.getUserList();
            if (users == null) {
                throw new Exception("Pusta lista użytkowników");
            }
        } catch (Exception ex) {
            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                    "Nie można wyświetlić tabeli wyników",
                    "Nie udało się pobrać danych, prosimy spróbować ponownie później.");
            FacesContext.getCurrentInstance().addMessage(null, message);
        }
    }

    /**
     * Get list of leaked Data.
     * If list is null then getDataFromDatabase method is used.
     * @see DataExplorer.getDataFromDatabase()
     */
    public List<UserDAO> getUsers() {
        if (users == null) {
            getDataFromDatabase();
        }
        return users;
    }

    private SelectItem[] createFilterOptions() {
        SelectItem[] options = new SelectItem[3];
        options[0] = new SelectItem("", "-select-");
        options[1] = new SelectItem("true", "Admins");
        options[2] = new SelectItem("false", "Users");

        return options;
    }

    public void onEditRow(RowEditEvent event){ 
        UserDAO userDAO = (UserDAO)event.getObject();
        try {
            userDAO.update();
        } catch (UserDAOException ex) {
            Log.logger.error("User not edited,"+ex);
        }
        //getDataFromDatabase();
    }
}

Upvotes: 1

Views: 6250

Answers (3)

vizzdoom
vizzdoom

Reputation: 736

Problem solved. There are extra h:form around p:inputText =_=

Upvotes: 1

Cagatay Civici
Cagatay Civici

Reputation: 6504

You are always returning a new list which is a well known bad practice in JSF, fetching data in getter. Getters may be called several times during JSF lifecycle. Cache your user list in a variable and better to use view scope.

Inline edit/update actually works but you are losing the updated model by returning a new list every time.

Upvotes: 4

spauny
spauny

Reputation: 5106

I don't know if I really understood your problem but you can easily update your table or even better update your form but implementing a commandButton with update attribute:

Let's say you have a form and it's id is myTableForm, then inside that form you have your dataTable component and a commandButton component. This button will look like this:

<p:commandButton ajax='true' value='PersistData' update='myTableForm' action='if really needed' />

You can refer to an action method only if you need to. Otherwise this button will only update your entire form by implementing an ajax request. Ajax is by default true, but I added that attribute there for explicitly.

Of course you can have another logic design...you don't have to implement a button to do that, you could have some ajax listeners, some javascript functions that will be triggered at page load, edit cells etc... I have chosen a commandButton because it's the easiest way to understand the logic...

Please let me know if this was really what you wanted.

Upvotes: 1

Related Questions