p:dataTable过滤,排序,分页的结果显示在一行中

时间:2018-11-01 20:43:50

标签: jsf primefaces

我正在为使用PrimeFaces 6.2(社区版)制作的应用程序设计主题,并且在继续进行CSS模板制作之前,我希望模拟的DAO对象能够正常工作。

我遇到了一个过去遇到的问题,但我找不到合适的答案了。有人会指出我在代码中某处犯了一个错误吗?

详细信息:

我已经使用PrimeFaces LazyDataModel制作了一个稍微复杂的DataTable,而没有PrimeFaces Showcase页面的帮助。我的主要问题是,当我在过滤器字段中编写内容或单击任何列标题进行数据排序,甚至单击分页按钮时,都遇到了未扩展的数据呈现问题。

过滤,排序和分页的结果显示在我不希望的单个链接行中。我在下面进一步发布了图片和代码以供深入了解。

此外,我想指出:

  • JS控制台中没有例外。
  • Java控制台中没有例外。
  • 不要介意缺少分页图标(文本缩进:0;

Before filtering

After filtering

XHTML:

<h:form id="input-form-dt2">
    <H4>DATA TABLE - LAZY MODEL</H4>
    <div class="flex-container">
        <p:outputPanel id="dev-input-panel-13">
            <p:dataTable var="DOTable" value="#{dtModelLazy.DOTList}" paginator="true" rows="10" rowKey="#{DOTable.userID}" 
                         paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
                         rowsPerPageTemplate="5,10,15,25,50" selectionMode="single" selection="#{dtModelLazy.selectedObj}" id="DTModelB" lazy="true">
                <p:ajax event="rowSelect" listener="#{dtModelLazy.onRowSelect}" update="input-form-dt2:dlgDTOObjDetail" oncomplete="PF('DTObjDialog').show()" />
                <p:column headerText="User ID" sortBy="#{DOTable.userID}" filterBy="#{DOTable.userID}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.userID}" />
                </p:column>
                <p:column headerText="Name" sortBy="#{DOTable.name}" filterBy="#{DOTable.name}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.name}" />
                </p:column>
                <p:column headerText="Surname" sortBy="#{DOTable.surname}" filterBy="#{DOTable.surname}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.surname}" />
                </p:column>
                <p:column headerText="Age" sortBy="#{DOTable.age}" filterBy="#{DOTable.age}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.age}" />
                </p:column>
                <p:column headerText="Address" sortBy="#{DOTable.address}" filterBy="#{DOTable.address}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.address}" />
                </p:column>
                <p:column headerText="City" sortBy="#{DOTable.city}" filterBy="#{DOTable.city}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.city}" />
                </p:column>
                <p:column headerText="Post code" sortBy="#{DOTable.postCode}" filterBy="#{DOTable.postCode}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.postCode}" />
                </p:column>
                <p:column headerText="Country code" sortBy="#{DOTable.countryCode}" filterBy="#{DOTable.countryCode}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.countryCode}" />
                </p:column>
                <p:column headerText="Phone number" sortBy="#{DOTable.phoneNumber}" filterBy="#{DOTable.phoneNumber}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.phoneNumber}" />
                </p:column>
                <p:column headerText="Avatar hash" sortBy="#{DOTable.photoID}" filterBy="#{DOTable.photoID}" filterMatchMode="contains">
                    <h:outputText value="#{DOTable.photoID}" />
                </p:column>
            </p:dataTable>
            <p:dialog id="dlgDTOObjDetail" header="DataTable Object Detail" widgetVar="DTObjDialog" modal="true" showEffect="fade" hideEffect="fade" resizable="false">
                <p:outputPanel id="DTObjDetail">
                    <p:panelGrid  columns="2" rendered="#{not empty dtModelLazy.selectedObj}" columnClasses="label,value">
                        <h:outputText value="User ID: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.userID}" />
                        <h:outputText value="Name: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.name}" />
                        <h:outputText value="Surname: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.surname}" />
                        <h:outputText value="Age: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.age}" />
                        <h:outputText value="Address: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.address}" />
                        <h:outputText value="City: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.city}" />
                        <h:outputText value="Post code: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.postCode}" />
                        <h:outputText value="Country code: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.countryCode}" />
                        <h:outputText value="Phone number: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.phoneNumber}" />
                        <h:outputText value="Photo hash: " />
                        <h:outputText value="#{dtModelLazy.selectedObj.photoID}" /> 
                    </p:panelGrid>
                </p:outputPanel>
            </p:dialog>
        </p:outputPanel>
    </div>
    <hr></hr>
</h:form>

延迟模式:

public class DataTableModelLazy extends LazyDataModel<DODataTable> {
    private static final long serialVersionUID = -2647349397077805782L;

    private List<DODataTable> datasource;

    public DataTableModelLazy(List<DODataTable> datasource) {
        this.datasource = datasource;
    }

    @Override
    public DODataTable getRowData(String rowKey) {
        for(DODataTable dtObj : datasource) {
            if(dtObj.getUserID().equals(rowKey))
                return dtObj;
        }

        return null;
    }

    @Override
    public Object getRowKey(DODataTable dtObj) {
        return dtObj.getUserID();
    }

    @Override
    public List<DODataTable> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,Object> filters) {
        List<DODataTable> data = new ArrayList<DODataTable>();

        //filter
        for(DODataTable dtObj : datasource) {
            boolean match = true;

            if(filters != null) {
                for (Iterator<String> it = filters.keySet().iterator(); it.hasNext();) {
                    try {
                        String filterProperty = it.next();
                        Object filterValue = filters.get(filterProperty);
                        Field field = dtObj.getClass().getDeclaredField(filterProperty);
                        field.setAccessible(true);
                        String fieldValue = String.valueOf(field.get(dtObj));
                        field.setAccessible(false);
                        if(filterValue == null || fieldValue.startsWith(filterValue.toString())) {
                            match = true;
                        } else {
                            match = false;
                            break;
                        }
                    } catch(Exception e) {
                        match = false;
                    }
                }
            } 
            if(match) {
                data.add(dtObj);
            }
        }

        //sort
        if(sortField != null) {
            Collections.sort(data, new DataTableModelLazySorter(sortField, sortOrder));
        }

        //rowCount
        int dataSize = data.size();
        this.setRowCount(dataSize);

        //paginate
        if(dataSize > pageSize) {
            try {
                return data.subList(first, first + pageSize);
            } catch(IndexOutOfBoundsException e) {
                return data.subList(first, first + (dataSize % pageSize));
            }
        } else {
            return data;
        }
    }
}

VIEW BEAN:

@Named("dtModelLazy")
@ViewScoped
public class DataGeneratorBeanLazy implements Serializable {
    private static final long serialVersionUID = -5918527333909822277L;

    private LazyDataModel<DODataTable> DOTList;
    private DODataTable selectedObj;

    @Inject
    private DataGeneratorBean dataGen;

    @PostConstruct
    public void init() {
        DOTList = new DataTableModelLazy(dataGen.createDTObjects(1500));
    }

    public LazyDataModel<DODataTable> getDOTList() {
        return DOTList;
    }

    public void setDOTList(LazyDataModel<DODataTable> dOTList) {
        DOTList = dOTList;
    }

    public void onRowSelect(SelectEvent event) {
        FacesMessage msg = new FacesMessage("DataTable object selected!", ((DODataTable) event.getObject()).getUserID());
        FacesContext.getCurrentInstance().addMessage(null, msg);
    }

    public DODataTable getSelectedObj() {
        return selectedObj;
    }

    public void setSelectedObj(DODataTable selectedObj) {
        this.selectedObj = selectedObj;
    }

}

更新1

我已将update属性修改为update="input-form-dt2:dlgDTOObjDetail",以满足提出的建议。另外,我为对话框添加了id属性。问题仍然存在。

更新2

我改变了方法,首先从基本的DataTable开始。另外,我将.xhtml剥离到最低限度。它仅包含一个带有DataTable的表单,如下所示:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"   
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:p="http://primefaces.org/ui">
    <div>
        UI components design
    </div>

    <h:form id="input-form-dt1">
        <h4>DATA TABLE - BASIC</h4>
        <p:dataTable id="DTableA" var="dataObject" value="#{dataTableBean.objectList}" paginator="true" rows="10" rowKey="#{dataObject.id}" 
                     paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}" 
                     rowsPerPageTemplate="5,10,15,25,50">
            <p:column headerText="User ID" sortBy="#{dataObject.userID}" filterBy="#{dataObject.userID}" filterMatchMode="contains">
                <h:outputText value="#{dataObject.userID}" />
            </p:column>
            <p:column headerText="Name" sortBy="#{dataObject.name}" filterBy="#{dataObject.name}" filterMatchMode="contains" >
                <h:outputText value="#{dataObject.name}" />
            </p:column>
            <p:column headerText="Surname" sortBy="#{dataObject.surname}" filterBy="#{dataObject.surname}" filterMatchMode="contains" >
                <h:outputText value="#{dataObject.surname}" />
            </p:column>
            <p:column headerText="Age" sortBy="#{dataObject.age}" filterBy="#{dataObject.age}" filterMatchMode="contains" >
                <h:outputText value="#{dataObject.age}" />
            </p:column>
            <p:column headerText="Address" sortBy="#{dataObject.address}" filterBy="#{dataObject.address}" filterMatchMode="contains" >
                <h:outputText value="#{dataObject.address}" />
            </p:column>
            <p:column headerText="City" sortBy="#{dataObject.city}" filterBy="#{dataObject.city}" filterMatchMode="contains" >
                <h:outputText value="#{dataObject.city}" />
            </p:column>
            <p:column headerText="Post code" sortBy="#{dataObject.postCode}" filterBy="#{dataObject.postCode}" filterMatchMode="contains" >
                <h:outputText value="#{DOTable.postCode}" />
            </p:column>
            <p:column headerText="Country code" sortBy="#{dataObject.countryCode}" filterBy="#{dataObject.countryCode}" filterMatchMode="contains" >
                <h:outputText value="#{dataObject.countryCode}" />
            </p:column>
            <p:column headerText="Phone number" sortBy="#{dataObject.phoneNumber}" filterBy="#{dataObject.phoneNumber}" filterMatchMode="contains" >
                <h:outputText value="#{dataObject.phoneNumber}" />
            </p:column>
            <p:column headerText="Avatar hash" sortBy="#{dataObject.photoID}" filterBy="#{dataObject.photoID}" filterMatchMode="contains">
                <h:outputText value="#{dataObject.photoID}" />
            </p:column>
        </p:dataTable>
    </h:form>
</ui:composition>

如您所见,我还删除了所有事件监听器。我在我的数据对象(ID为Integer类型)中添加了一个新字段,并将DataTables rowKey绑定到了该字段(以前绑定为String类型的userID-这不是一个好主意)。我的DataTable支持bean现在已尽可能地基本:

@Named("dataTableBean")
@ViewScoped
public class DataTableBean implements Serializable {
    private static final long serialVersionUID = -1662465661106141910L;

    private List<DTObject> objectList;

    @Inject
    private DataGeneratorBean dataGen;

    @PostConstruct
    public void init() {
        setObjectList(dataGen.createDTObjects(1500));
    }

    public List<DTObject> getObjectList() {
        if (objectList == null) {
            return new ArrayList<>();
        } else {
            return objectList;
        }
    }

    public void setObjectList(List<DTObject> objectList) {
        this.objectList = objectList;
    }

}

现在,没有任何类型的自定义过滤器,排序器或分页器,甚至没有数据模型,只是简单列表中的原始数据对象。 单击分页器按钮或过滤数据后,输出结果与以前完全相同。所有产生的数据仍会显示在一条串联的行中。

答案:

正如 Kukeltje 在评论中指出的那样,我已经在我的主容器中做了完全废话,并在其中添加了自动更新组件。该组件弄乱了我的数据表事件,在没有表保存的情况下加载数据。一旦从主容器中删除了组件,一切就完成了。这是我的主容器的代码(注释了麻烦制造者)。

<div id="content-window">
    <p:outputPanel id="content-panel">
        <ui:include src="#{contentLoaderBean.mainContent}" />
        <!-- <p:autoUpdate /> -->
    </p:outputPanel>
</div>

1 个答案:

答案 0 :(得分:1)

我看到的唯一情况是,通过事件(页面或过滤器或排序或...)对数据表进行了部分更新,然后对数据表进行了完全更新。包含数据表的完整表格。这是不好的做法,并且如上所述,它可能会导致您所看到的情况。

但是...在您的问题中,没有可以显式更新完整数据表的过滤器ajax事件,因此不会导致该问题。但是具有99%的准确性,有些东西可以完全更新数据表。三种选择

  • 您的实时代码中有某些内容被您问题中的数据表遗漏了
  • 您发布的代码之外还有其他内容会造成破坏(例如自动更新)
  • 正在通过一种方法从服务器端进行更新