Jsf 2 Primefaces数据表日期范围筛选器,带filterFunction
我在PrimeFaces5.0上使用datatable的filterFunction方法。我想按列标题上的日期范围筛选生日 在浏览器控制台上,我收到以下错误:Jsf 2 Primefaces数据表日期范围筛选器,带filterFunction,jsf-2,primefaces,datatable,classcastexception,Jsf 2,Primefaces,Datatable,Classcastexception,我在PrimeFaces5.0上使用datatable的filterFunction方法。我想按列标题上的日期范围筛选生日 在浏览器控制台上,我收到以下错误: <?xml version="1.0" encoding="utf-8"?><partial-response><error><error-name>java.lang.ClassCastException</error-name><error-message>
<?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>
java.lang.ClassCastException
数据表:
<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>
豆子:
@组件(“testDateRange”)
@范围(“会议”)
公共类TestDateRangeBean{
私人名单人员;
列出筛选人员;
私人日期从;
私人日期至;
公共TestDateRangeBean(){
persons=新建ArrayList(Arrays.asList(
新人(“约翰”,新日期(1357016400000L)),
新人(“遗嘱”,新日期(1357102800000L)),
新人(“彼得”,新日期(141490080000L)),
新人员(“Cris”,新日期(1438747200000L)),
新人员(“Cemil”,新日期(14306800000L))
));
}
公共布尔筛选器ByDate(对象值、对象筛选器、区域设置){
//它在调用此方法之前失败
字符串filterText=(filter==null)?null:filter.toString().trim();
if(StringUtils.isEmpty(filterText)){
返回true;
}
如果(值==null){
返回false;
}
DateFormat df=新的简化格式(“dd/MM/yyyy”);
日期过滤器日期;
试一试{
filterDate=df.parse(filterText);
}捕获(解析异常){
返回false;
}
返回filterDate.after(dateFrom)和filterDate.before(dateTo);
}
//所有的能手和二传手
我有一个简单的pojoperson类,它只包含“name”和“birth”
如何根据在列标题中输入的日期筛选生日。我看到它得到的是UIPanel组件而不是dates值。(我假设它需要一个组件带有一个值,当它找到两个组件时,它会返回容器组件本身,对吗?)
谢谢遇到了同样的问题,但在我的例子中,它是过滤器方面的按钮,用于显示覆盖面板,其中包含范围滑块 要解决此问题,请改用header方面:
<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组件中不需要更新属性。高级解决方案:
JSF:
如果您不想使用隐藏的输入字段加上重用这样的过滤器的好处,请考虑编写一个复合组件,其组件类型扩展了javax .FACK.Engult.UInPurrime.PrimeFrases预期过滤器是Javax、Fase.Cuff.ValueHORK./P>的子类型。 这就是复合组件的外观
<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>
复合组件采用的值是一个简单的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>
整个事情都会像这样
这只是@Stephan答案的Java 8实现,使用Java.time类而不是Date 除了日期模式外,JSF部分几乎相同
<p:column headerText="Date" filterBy="#{passbook.createdAt}" filterFunction="#{applicationController.filterByDate}">
<f:facet name="filter">
<h:inputHidden id="filter" />
</f:facet>
<f:facet name="header">
<h:outputText value="Date" />
<br />
<p:calendar id="from" pattern="dd-MMM-yyyy" size="12">
<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('passbookTable').filter()" />
</p:calendar>
<h:outputText class="fa fa-arrows-h fa-2x" style="vertical-align: top;"/>
<p:calendar id="to" pattern="dd-MMM-yyyy" size="12">
<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('passbookTable').filter()" />
</p:calendar>
</f:facet>
<h:outputText value="#{passbook.createdAt}">
<f:convertDateTime type="date" dateStyle="medium" pattern="dd-MMM-yyyy"/>
</h:outputText>
有一个问题,在用法部分,有一个
@ochi,它是一个随机选取的名称空间,在本例中xmlns:clx=”http://xmlns.jcp.org/jsf/composite/clxcomponents"
。有关如何使用复合组件的快速介绍,请阅读此建议组件,谢谢。我的问题是,虽然dateRange
是ValueHolder
的子类型,但值不会发送到筛选器。当我将值的类型更改为字符串时,它会工作。如何发送dateRange值到筛选器?您好。感谢您的贡献。我尝试在延迟加载的datatable上使用此组件,但我不知道如何处理value属性。您知道如何在加载方法的筛选器映射上检索所选对象吗?因为我使用了filter而不使用filterFunction,所以我必须重写getLocalValue以返回insuper.getLocalValue()时DateRange的状态为空。当我在筛选器中使用
时,我得到java.lang.ClassCastException:javax.faces.component.UIPanel不能转换为javax.faces.component.ValueHolder,并且筛选器不工作。我假设h:inputHidden不能在筛选器中。好的,问题在注释中。它需要被删除或放入删除标记:e> 。感谢您的建议,+1…顺便说一句,日期解析无法在多个地区工作…因此,由于您正在强制以“dd.MM.yyyy”格式保存到HTML隐藏字段中,因此最好使用相同的格式在FilterBean中初始化DateFormat:DateFormat df=new SimpleDataFormat(“dd.MM.yyyy”);这应该成为下一个@Primefaces发行版的一部分。就像filterMode=“date\u range”或filterMode=“dates”
一样。请问@Scope
和@组件从哪里来?
@FacesComponent("dateRange")
public class DateRangeComponent extends UIInput implements NamingContainer {
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
}
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>
public boolean filterByDate(Object value, Object filter, Locale locale) {
Date colDate = (Date) value;
return this.range.getFrom().before(colDate) && this.range.getTo().after(colDate);
}
<p:column headerText="Date" filterBy="#{passbook.createdAt}" filterFunction="#{applicationController.filterByDate}">
<f:facet name="filter">
<h:inputHidden id="filter" />
</f:facet>
<f:facet name="header">
<h:outputText value="Date" />
<br />
<p:calendar id="from" pattern="dd-MMM-yyyy" size="12">
<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('passbookTable').filter()" />
</p:calendar>
<h:outputText class="fa fa-arrows-h fa-2x" style="vertical-align: top;"/>
<p:calendar id="to" pattern="dd-MMM-yyyy" size="12">
<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('passbookTable').filter()" />
</p:calendar>
</f:facet>
<h:outputText value="#{passbook.createdAt}">
<f:convertDateTime type="date" dateStyle="medium" pattern="dd-MMM-yyyy"/>
</h:outputText>
@Named
@ApplicationScoped
public class ApplicationController implements Serializable {
private static final Logger logger = LogManager.getLogger(ApplicationController.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;
}
DateTimeFormatter sdf = DateTimeFormatter.ofPattern("dd-MMM-yyyy");
Instant instant = ((Date) value).toInstant(); //Zone : UTC+0
LocalDate dateValue = instant.atZone(ZoneId.of("Asia/Kolkata")).toLocalDate();
LocalDate dateFrom;
LocalDate dateTo;
try {
String fromPart = filterText.substring(0, filterText.indexOf(">"));
String toPart = filterText.substring(filterText.indexOf(">") + 1);
dateFrom = fromPart.isEmpty() ? null : LocalDate.parse(fromPart, sdf);
dateTo = toPart.isEmpty() ? null : LocalDate.parse(toPart, sdf);
} catch (Exception e) {
logger.error("unable to parse date: " + filterText, e);
return false;
}
return (dateFrom == null || dateValue.isAfter(dateFrom) || dateValue.isEqual(dateFrom))
&& (dateTo == null || dateValue.isBefore(dateTo) || dateValue.isEqual(dateTo));
}