p: dataTable отфильтрованные, отсортированные, разбитые на страницы результаты отображаются в одной строке - PullRequest
0 голосов
/ 01 ноября 2018

Я работаю над темой для приложения, которое создаю с помощью PrimeFaces 6.2 (версия для сообщества), и я хотел бы, чтобы мои смоделированные объекты DAO работали, прежде чем я приступлю к шаблонам CSS.

У меня есть проблема, с которой я сталкивался в прошлом, и я не могу найти правильный ответ для нее снова. Кто-нибудь укажет на ошибку, которую я сделал где-то в моем коде?

Детали:

Я сделал несколько сложную DataTable, используя PrimeFaces LazyDataModel с небольшой помощью страниц демонстрации PrimeFaces. Моя основная проблема заключается в том, что когда я что-то записываю в поля фильтра или щелкаю по заголовкам столбцов, чтобы выполнить сортировку данных, или даже нажимаю на кнопки разбиения на страницы, я получаю неэкспонированную проблему рендеринга данных.

Отфильтрованные, отсортированные и разбитые на страницы результаты отображаются в единой объединенной строке, что мне не нужно . Я разместил изображения и код ниже для понимания.

Также я бы хотел отметить:

  • Нет исключений в консоли 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;
        }
    }
}

ПРОСМОТР БИНА:

@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="input-form-dt2:dlgDTOObjDetail", чтобы удовлетворить предложенное предложение. Также я добавил свойство id для диалога. Проблема все еще остается.

Обновление 2

Я изменил свой подход и сначала начал с базовой таблицы данных. Кроме того, я сократил .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>

Как видите, я также удалил всех слушателей событий. Я добавил новое поле в мой объект данных (идентификатор типа Integer) и привязал к нему DataTables rowKey (ранее привязанный к userID типа String - не очень хорошая идея). Мой компонент поддержки DataTable теперь настолько прост, насколько может быть:

@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 голосов
/ 04 ноября 2018

Единственное, что я видел, это происходило, когда таблица данных полностью обновлялась в дополнение к частичному обновлению таблицы данных с помощью события (страницы, фильтра или сортировки или ...). В rowSelect вы, кажется, обновляете полная форма, которая также содержит данные. Это плохая практика и, как уже упоминалось, может привести к тому, что вы, похоже, удалите это.

Но ... в вашем вопросе нет событий фильтра ajax, которые явно обновляют полный набор данных, поэтому не могут его вызвать. Тем не менее, с 99% достоверностью есть что-то, что полностью обновляет данные. Три варианта

  • в вашем живом коде есть что-то, что вы исключили из таблицы данных в своем вопросе
  • Есть что-то еще, кроме того, что вы опубликовали код, который играет хаос (например, автообновление),
  • обновление со стороны сервера выполняется методом
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...