我在PrimeFaces5.0上使用datatable的filterFunction方法。我想在列标题上按日期范围过滤生日。
在浏览器控制台上,我收到以下错误:
<?xml version="1.0"
encoding="utf-8"?><partial-response><error><error-name>java.lang.ClassCastException</error-name><error-message><![CDATA[javax.faces.component.UIPanel
cannot be cast to
javax.faces.component.ValueHolder]]></error-message></error></partial-response>
数据表:
<p:dataTable var="person" value="#{testDateRange.persons}"
id="personTable" paginator="true" styleClass="customTableStyle" editable="true"
rows="10" resizableColumns="true"
emptyMessage="No persons"
filteredValue="#{testDateRange.filteredPersons}"
widgetVar="dateRangeWidget" >
<p:column id="nameId" filterBy="name" sortBy="name" filterMatchMode="contains" headerText="Name">
<h:outputText value="#{person.name}" />
</p:column>
<p:column id="birthdayId" headerText="birthday" filterBy="birthday" filterFunction="#{testDateRange.filterByDate}">
<f:facet name="filter">
<p:calendar id="from" value="#{testDateRange.dateFrom}" styleClass="customCalendar" pattern="dd/MM/yyyy">
<p:ajax event="dateSelect" oncomplete="PF('dateRangeWidget').filter()" update="personTable"/>
</p:calendar>
<p:calendar id="to" value="#{testDateRange.dateTo}" styleClass="customCalendar" pattern="dd/MM/yyyy">
<p:ajax event="dateSelect" oncomplete="PF('dateRangeWidget').filter()" update="personTable"/>
</p:calendar>
</f:facet>
<h:outputText value="#{person.birthday}" >
<f:convertDateTime pattern="dd/MM/yyyy"/>
</h:outputText>
</p:column>
</p:dataTable>
豆子:
@Component("testDateRange")
@Scope("session")
public class TestDateRangeBean {
private List<Person> persons;
List<Person> filteredPersons;
private Date dateFrom;
private Date dateTo;
public TestDateRangeBean() {
persons = new ArrayList<>(Arrays.asList(
new Person("John", new Date(1357016400000L)),
new Person("Will",new Date(1357102800000L)),
new Person("Peter",new Date(1414900800000L)),
new Person("Cris", new Date(1438747200000L)),
new Person("Cemil", new Date(1436068800000L))
));
}
public boolean filterByDate(Object value, Object filter, Locale locale) {
// it fails before calling this method
String filterText = (filter == null) ? null : filter.toString().trim();
if(StringUtils.isEmpty(filterText)) {
return true;
}
if(value == null) {
return false;
}
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
Date filterDate;
try {
filterDate = df.parse(filterText);
} catch (ParseException e) {
return false;
}
return filterDate.after(dateFrom) && filterDate.before(dateTo);
}
//all the getters and setters
我有一个简单的POJO Person类,它只包含'name‘和’生日‘。
如何根据在列标题上输入的日期筛选生日。我看到它得到的是UIPanel组件,而不是日期值。(我假设它期望一个组件具有一个值,当它找到两个组件时,它会返回容器组件本身,对吗?)
谢谢
发布于 2014-09-15 23:08:17
高级解决方案:
JSF:
<p:column headerText="#{msg.date}" sortBy="#{bean.date}" filterBy="#{bean.date}" filterFunction="#{dateRangeFilter.filterByDate}">
<f:facet name="filter">
<h:inputHidden id="filter" />
</f:facet>
<f:facet name="header">
<h:outputText value="#{msg.date}" />
<br />
<p:calendar id="from" pattern="dd.MM.yyyy">
<p:ajax event="dateSelect" onstart="$(PrimeFaces.escapeClientId('#{p:component('filter')}'))[0].value = $(PrimeFaces.escapeClientId('#{p:component('from')}_input'))[0].value + '-' + $(PrimeFaces.escapeClientId('#{p:component('to')}_input'))[0].value" oncomplete="PF('dataTable').filter()" />
</p:calendar>
<p:calendar id="to" pattern="dd.MM.yyyy">
<p:ajax event="dateSelect" onstart="$(PrimeFaces.escapeClientId('#{p:component('filter')}'))[0].value = $(PrimeFaces.escapeClientId('#{p:component('from')}_input'))[0].value + '-' + $(PrimeFaces.escapeClientId('#{p:component('to')}_input'))[0].value" oncomplete="PF('dataTable').filter()" />
</p:calendar>
</f:facet>
<h:outputText value="#{bean.date}">
<f:convertDateTime type="date" dateStyle="medium" />
</h:outputText>
</p:column>
过滤豆:
@Named
@ApplicationScoped
public class DateRangeFilter implements Serializable {
private static final Logger LOG = Logger.getLogger(DateRangeFilter.class.getName());
public boolean filterByDate(Object value, Object filter, Locale locale) {
String filterText = (filter == null) ? null : filter.toString().trim();
if (filterText == null || filterText.isEmpty()) {
return true;
}
if (value == null) {
return false;
}
DateFormat df = SimpleDateFormat.getDateInstance(SimpleDateFormat.MEDIUM);
Date filterDate = (Date) value;
Date dateFrom;
Date dateTo;
try {
String fromPart = filterText.substring(0, filterText.indexOf("-"));
String toPart = filterText.substring(filterText.indexOf("-") + 1);
dateFrom = fromPart.isEmpty() ? null : df.parse(fromPart);
dateTo = toPart.isEmpty() ? null : df.parse(toPart);
} catch (ParseException pe) {
LOG.log(Level.SEVERE, "unable to parse date: " + filterText, pe);
return false;
}
return (dateFrom == null || filterDate.after(dateFrom)) && (dateTo == null || filterDate.before(dateTo));
}
}
发布于 2015-03-06 14:18:41
如果您不想使用隐藏的输入字段,再加上重用这样一个过滤器的好处,请考虑编写一个组件类型扩展为javax.faces.component.UIInput的复合组件。Primefaces期望过滤器是javax.faces.component.ValueHolder的一个子类型。
这就是复合组件的样子。
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<!-- INTERFACE -->
<cc:interface componentType="dateRange">
<cc:attribute name="fromLabel"/>
<cc:attribute name="toLabel"/>
<cc:attribute name="value" type="so.example.DateRange"/>
<cc:attribute name="onvaluechanged"/>
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<table>
<tr>
<td style="width: 15%; border: none;">
<h:outputText value="#{cc.attrs.fromLabel}"/>
</td>
<td style="width: 35%; border: none;">
<p:calendar id="startDateCalendar" value="#{cc.attrs.value.from}" maxdate="#{cc.attrs.value.to}">
<p:ajax event="dateSelect" update="endDateCalendar" oncomplete="#{cc.attrs.onvaluechanged}"/>
</p:calendar>
</td>
<td style="width: 15%; border: none;">
<h:outputText value="#{cc.attrs.toLabel}"/>
</td>
<td style="width: 35%; border: none;">
<p:calendar id="endDateCalendar" value="#{cc.attrs.value.to}" mindate="#{cc.attrs.value.from}" maxdate="#{cc.attrs.value.now}">
<p:ajax event="dateSelect" update="startDateCalendar" oncomplete="#{cc.attrs.onvaluechanged}"/>
</p:calendar>
</td>
</tr>
</table>
</cc:implementation>
注意componentType="dateRange"
标记中的cc:interface
。这引用了这个复合组件的根组件类。很简单,就像。
@FacesComponent("dateRange")
public class DateRangeComponent extends UIInput implements NamingContainer {
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
}
复合组件的值是一个简单的POJO。
public class DateRange implements Serializable {
private Date from;
private Date to;
private boolean ignoreTime = true;
public Date getFrom() {
return from;
}
public void setFrom(Date from) {
if (this.isIgnoreTime()) {
Calendar now = Calendar.getInstance();
now.setTime(from);
now.set(Calendar.HOUR_OF_DAY, 0);
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
this.from = now.getTime();
} else {
this.from = from;
}
}
public Date getTo() {
return to;
}
public void setTo(Date to) {
if (this.isIgnoreTime()) {
Calendar now = Calendar.getInstance();
now.setTime(to);
now.set(Calendar.HOUR_OF_DAY, 23);
now.set(Calendar.MINUTE, 59);
now.set(Calendar.SECOND, 59);
this.to = now.getTime();
} else {
this.to = to;
}
}
public Date getNow() {
return new Date();
}
public boolean isIgnoreTime() {
return ignoreTime;
}
public void setIgnoreTime(boolean ignoreTime) {
this.ignoreTime = ignoreTime;
}
}
毕竟,这个用法非常简单。
<p:column headerText="#{labels.date}"
sortBy="#{logIn.loginDate}"
filterBy="#{logIn.loginDate}"
filterFunction="#{logInTableBean.filterByDate}"
styleClass="datetime-column">
<f:facet name="filter">
<clx:dateRange fromLabel="#{labels.from}"
toLabel="#{labels.to}"
onvaluechanged="PF('logInTable').filter();"
value="#{logInTableBean.range}"/>
</f:facet>
<h:outputText value="#{logIn.loginDate}">
<f:convertDateTime type="both" dateStyle="long"/>
</h:outputText>
</p:column>
还请注意自定义筛选器函数。Whis就像
public boolean filterByDate(Object value, Object filter, Locale locale) {
Date colDate = (Date) value;
return this.range.getFrom().before(colDate) && this.range.getTo().after(colDate);
}
整件事都是这样的。
发布于 2014-09-13 04:41:37
遇到了同样的问题,但在我的情况下,它是在过滤器方面显示覆盖面板与范围滑块内按钮。
要解决这个问题,请使用报头面来代替:
<f:facet name="filter">
<!-- to hide default filter input -->
<h:inputHidden />
</f:facet>
<f:facet name="header">
<p:outputLabel value="birthday" /><br />
<p:calendar id="from" value="#{testDateRange.dateFrom}" styleClass="customCalendar" pattern="dd/MM/yyyy">
<p:ajax event="dateSelect" oncomplete="PF('dateRangeWidget').filter()" />
</p:calendar>
<p:calendar id="to" value="#{testDateRange.dateTo}" styleClass="customCalendar" pattern="dd/MM/yyyy">
<p:ajax event="dateSelect" oncomplete="PF('dateRangeWidget').filter()" />
</p:calendar>
</f:facet>
此外,在p:ajax组件中没有必要使用update属性。
https://stackoverflow.com/questions/23791039
复制相似问题