Я работаю над темой для приложения, которое создаю с помощью PrimeFaces 6.2 (версия для сообщества), и я хотел бы, чтобы мои смоделированные объекты DAO работали, прежде чем я приступлю к шаблонам CSS.
У меня есть проблема, с которой я сталкивался в прошлом, и я не могу найти правильный ответ для нее снова. Кто-нибудь укажет на ошибку, которую я сделал где-то в моем коде?
Детали:
Я сделал несколько сложную DataTable, используя PrimeFaces LazyDataModel с небольшой помощью страниц демонстрации PrimeFaces. Моя основная проблема заключается в том, что когда я что-то записываю в поля фильтра или щелкаю по заголовкам столбцов, чтобы выполнить сортировку данных, или даже нажимаю на кнопки разбиения на страницы, я получаю неэкспонированную проблему рендеринга данных.
Отфильтрованные, отсортированные и разбитые на страницы результаты отображаются в единой объединенной строке, что мне не нужно . Я разместил изображения и код ниже для понимания.
Также я бы хотел отметить:
- Нет исключений в консоли JS.
- Нет исключений в консоли Java.
- не обращайте внимания на отсутствующие значки нумерации страниц ( текстовый отступ: 0; )
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>