Доброго времени суток.
При методике разработки ПО, известной как copying and pasting from StackOverflow, зачастую приходится сталкиваться со странными ошибками, которые решаются по той же методике, что и привела к их появлению - поиску ответа в интернете (хотя зачастую внимательного изучения примера из официальной документации бывает достаточно). Именно поэтому я пишу эту статью - я столкнулся с некоторой проблемой при фильтрации таблиц (dataTable) в чудесной библиотеке компонентов Primefaces (в её реализации для JSF).
Итак, начнём с простейшего примера - без какой-либо фильтрации, только таблица.
@Data
@ManagedBean
@ViewScoped
public class TableTestBean implements Serializable {
private List<TableRow> rows;
@PostConstruct
public void init() {
rows = fillData();
}
private List<TableRow> fillData() {
// fill some data
}
@Data
@AllArgsConstructor
public static class TableRow implements Serializable {
private long id;
private String stringData;
private String anotherStringData;
}
}
<?xml version="1.0"?>
<f:view
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:head>
</h:head>
<h:body>
<h:form>
<p:dataTable value="#{tableTestBean.rows}" var="row">
<p:column headerText="Id">
<h:outputText value="#{row.id}"/>
</p:column>
<p:column headerText="First data">
<h:outputText value="#{row.stringData}"/>
</p:column>
<p:column headerText="Second data">
<h:outputText value="#{row.anotherStringData}"/>
</p:column>
</p:dataTable>
</h:form>
</h:body>
</f:view>
Вполне предсказуемо, этот пример работает. Попробуем расширить его - добавим фильтрацию по колонкам.
<p:dataTable value="#{tableTestBean.rows}" var="row">
<p:column headerText="Id">
<h:outputText value="#{row.id}"/>
</p:column>
<p:column headerText="First data" filterBy="#{row.stringData}" filterMatchMode="contains">
<h:outputText value="#{row.stringData}"/>
</p:column>
<p:column headerText="Second data" filterBy="#{row.anotherStringData}" filterMatchMode="contains">
<h:outputText value="#{row.anotherStringData}"/>
</p:column>
</p:dataTable>
Вроде бы всё так, как и должно быть - таблица успешно фильтруется.
До применения фильтра:
После применения фильтра:
Фильтр по другой колонке:
Но данный пример начинает себя вести неадекватно, стоит лишь добавить в него какие-либо инпуты.
<p:dataTable value="#{tableTestBean.rows}" var="row">
<p:column headerText="Id">
<h:outputText value="#{row.id}"/>
</p:column>
<p:column headerText="First data" filterBy="#{row.stringData}" filterMatchMode="contains">
<h:outputText value="#{row.stringData}"/>
</p:column>
<p:column headerText="Second data" filterBy="#{row.anotherStringData}" filterMatchMode="contains">
<p:inputText value="#{row.anotherStringData}" style="display: inline-block; width: 200px">
<p:ajax process="@this" update="@this out"/>
</p:inputText>
<h:outputText id="out" value="#{row.anotherStringData.toUpperCase()}"/>
</p:column>
</p:dataTable>
В третью колонку таблицы был добавлен инпут для редактирования соответствующего значения. И редактирование работает.
До редактирования:
После:
Но стоит лишь начать фильтровать, как происходит странная магия - первая строка начинает заполняться другими значениями.
До фильтрации:
После фильтрации:
После сброса фильтра (третья ячейка в первой строке изменилась):
Решение проблемы оказалось очень простым - нужно было лишь внимательно почитать документацию, из которой можно узнать, что при фильтрации таблицы необходимо указывать атрибут filteredValue, который будет хранить список строк, соответствующих фильтру. Таким образом, вносим изменения в бин: добавляем ещё один список для сохранения отфильтрованных значений, при инициализации заполняем его значениями из исходного списка.
private List<TableRow> filteredRows;
@PostConstruct
public void init() {
rows = fillData();
filteredRows = new ArrayList<>(rows);
}
и указываем новый атрибут у dataTable
<p:dataTable value="#{tableTestBean.rows}" filteredValue="#{tableTestBean.filteredRows}" var="row">
Проверяем работу.
До фильтра:
После фильтра:
После сброса фильтра (первая строка не изменилась):
Как видно, теперь при сбросе фильтра всё работает - значения в строках остаются теми же, что и до фильтрации.
Мораль проста: внимательно читайте документацию, чтобы не наталкиваться на такие досадные проблемы.
Засим откланиваюсь, прощайте.