Catfish
Catfish

Reputation: 19314

Primefaces datatable using LazyDataModel not updating. Seems like load method is not getting called

I'm using primefaces 4.0 datatable using a LazyDataModel. I'm also using the <p:rowEditor /> and when a row is edited and saved, my datatable data is not being updated. It seems that the LazyDataModel.load method is not called on an ajax update.

Is there something I'm doing wrong or a workaround? Is this a known problem?

LazyUserDataModel.java

public class LazyUserDataModel extends LazyDataModel<User> {

        private static final long serialVersionUID = -7759670987463023731L;
        private List<User> users;
        private Dao dao;
        private String username;
        private List<String> roles;

        public LazyUserDataModel(Dao dao, String username, List<String> roles) {
            this.dao = dao;
            this.username = username;
            this.roles = roles;
        }

        @Override  
        public List<User> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,String> filters) {  

            List<User> users = new ArrayList<User>();  
            users = dao.findAllUsers(username, roles, first, pageSize);
    ...

UserGroupBacking.java

...
    private LazyDataModel<User> users;

    @PostConstruct
        public void init() {
            this.ds = databaseBacking.getDs();
            if(isLoggedIn()) {
                loadData();
            }
        }

    public void updateUsersGroups(RowEditEvent event) {
        // Save data to db (this part works fine)
        loadData();
    }

    private void loadData() {
            Dao dao = new Dao(ds);
            users = new LazyUserDataModel(dao, accessBacking.getUsername(), accessBacking.getRoles());
        }
    ...

.xhtml

<p:tabView id="tabs">

    <p:tab id="userTab" title="Users">
        <h:form id="userForm">

            <p:growl for="growl" severity="info" autoUpdate="true" showDetail="true" />
            <p:messages id="userMessages" severity="error" showDetail="true" />

            <p:dataTable var="user" value="#{userGroupBacking.users}" editable="true" id="userTable" paginator="true" rows="20"  
                    paginatorTemplate="{CurrentPageReport}  {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}" lazy="true"
                    filteredValue="#{userGroupBacking.filteredUsers}" >

                <p:ajax event="rowEdit" listener="#{userGroupBacking.updateUsersGroups}" update=":tabs:userForm:userTable, :tabs:userForm:userMessages" /> 

                <p:column headerText="User" filterBy="#{user.name}" filterMatchMode="contains">
                    <h:outputText value="#{user.name}" />
                </p:column>

                <p:column headerText="Groups">
                    <p:cellEditor>
                        <f:facet name="output">
                            <ui:repeat var="group" value="#{user.groups}">
                                <h:outputText value="#{group.name}" /><br />
                            </ui:repeat>
                        </f:facet>
                        <f:facet name="input">
                            <p:selectCheckboxMenu value="#{user.groupsAsString}" label="Groups" filter="true" filterText="Filter" filterMatchMode="contains">
                                <f:selectItems value="#{userGroupBacking.groupsAsSelectItems}" />
                            </p:selectCheckboxMenu>
                        </f:facet>
                    </p:cellEditor>
                </p:column>
...

Upvotes: 4

Views: 9252

Answers (1)

BalusC
BalusC

Reputation: 1109570

It appears that the <p:ajax event="rowEdit"> does by design inside the table not update anything else than the edited row. Even not when explicitly specified by update attribute. It'll be plain ignored. This makes maybe sense, but this is IMO too overzealous and worth an issue report.

I did some digging in the source code, but it appears not to be easily and nicely possible to change/override this behavior. Your best bet is to perform the update of the entire table in a separate ajax request. The <p:remoteCommand> is helpful in this.

Instead of

<p:dataTable id="userTable" ...>
    <p:ajax event="rowEdit" listener="#{userGroupBacking.updateUsersGroups}" update=":tabs:userForm:userTable, :tabs:userForm:userMessages" /> 
    ...
</p:dataTable>

do

<p:remoteCommand name="updateUsersGroups" action="#{userGroupBacking.updateUsersGroups}" update="userTable userMessages" />
<p:dataTable id="userTable" ...>
    <p:ajax event="rowEdit" oncomplete="updateUsersGroups()" /> 
    ...
</p:dataTable>

and remove the RowEditEvent argument from the method.


By the way, instead of recreating the whole LazyDataModel in order to force a reload of the lazy data model, you could alternatively also just get a handle of DataTable component instance in some way (as method argument?) and invoke loadLazyData() method on it. E.g. via binding:

<p:remoteCommand name="updateUsersGroups" action="#{userGroupBacking.updateUsersGroups(userTable)}" update="userTable userMessages" />
<p:dataTable id="userTable" binding="#{userTable}" ...>
    <p:ajax event="rowEdit" oncomplete="updateUsersGroups()" /> 
    ...
</p:dataTable>

with

public void updateUsersGroups(DataTable table) {
    // ...
    table.loadLazyData();
}

Upvotes: 4

Related Questions