Custom filters and converters in p:dataTable

2019-08-15 03:35发布

Since PrimeFaces does not yet support converter for <p:dataTable> filters, I'm trying to implement my own custom filter for <p:calendar> (of course, the design of this filter still looks somewhat ugly. It needs to apply proper CSS that I cannot).

<p:column id="discountStartDate" sortBy="#{row.discountStartDate}" style="width:140px;">
    <f:facet name="header">
        Start Date<br/>

        <p:calendar id="startDateFilter" converter="#{dateTimeConverter}"
                    timeZone="Asia/Kolkata" locale="#{localeBean.locale}"
                    pattern="dd-MMM-yyyy hh:mm:ss a" 
                    readonly="#{facesContext.currentPhaseId.ordinal eq 6}"
                    label="Start Date"
                    effect="slide" required="true"
                    size="12"
                    showButtonPanel="true" navigator="true">

            <p:ajax event="dateSelect" listener="#{discountManagedBean.startDateListener}" 
                    onstart="PF('blockDataTableUIWidget').block()"
                    oncomplete="PF('blockDataTableUIWidget').unblock()"
                    update="dataTable"/>
        </p:calendar>

    </f:facet>

    <!--No need to refer to-->

    <p:cellEditor>
        <f:facet name="output">
            <h:outputText value="#{row.discountStartDate}" converter="#{dateTimeConverter}"/>
        </f:facet>
        <f:facet name="input">
            <p:tooltip for="dataTableTxtDiscountStartDate" value="#{messages['tooptip.dataTable.popup.calendar']}"/>
            <p:calendar id="dataTableTxtDiscountStartDate" binding="#{edStartDate}" value="#{row.discountStartDate}" converter="#{dateTimeConverter}" timeZone="Asia/Kolkata" locale="#{localeBean.locale}" pattern="dd-MMM-yyyy hh:mm:ss a" readonly="#{facesContext.currentPhaseId.ordinal eq 6}" label="#{messages['discount.startdate']}" effect="explode" required="true" showButtonPanel="true" navigator="true"/>
        </f:facet>
    </p:cellEditor>
</p:column>

When a date is selected from the calendar, the listener specified in <p:ajax> is invoked.

public void startDateListener(SelectEvent event)
{
    if(event.getObject() instanceof DateTime)
    {
        //org.joda.time.DateTime
        DateTime startDate=(DateTime) event.getObject();
        System.out.println(startDate+" : "+startDate.getZone().getID()+ " : "+startDate.getZone());
    }
}

The selected date is retrieved in this method but how can this date be used inside the load() method? <p:dataTable> uses org.primefaces.model.LazyDataModel<Discount>.

Is there a way to use this date from this listener method so that the data table - <p:dataTable> can be updated after filtering the rows based on the date supplied through the calendar - <p:calendar>?


How can this date can be used in the overridden load() method?

@Override
public List<Discount> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, String> filters)
{
     //Do something with filters to add the date selected from the calendar of the given filter we are talking about.

     return discountService.getList(first, pageSize, multiSortMeta, filters);
}

1条回答
来,给爷笑一个
2楼-- · 2019-08-15 04:07

There is a major enhancement in data table filters in PrimeFaces 5.0 final released on May 5, 2014.

PrimeFaces DataTable Filtering has been a useful feature to quickly filter data using ajax. However there were two main limitations; it was only based on string comparison and no support for custom filtering implementations. Thanks to a PrimeFaces PRO sponsorship, filtering is greatly enhanced for PF5.

Filter Facets

Filtering elements were limited to an input text and a native dropdown, now if an input component is defined using filter facet, it becomes the filter. This enables customizable UIs, ajax update support for filters, using objects instead of simple strings as filter values and more.

http://blog.primefaces.org/?p=3084

For example,

<p:column id="id" headerText="#{messages['id']}" sortBy="#{row.discountId}" filterBy="#{row.discountId}" filterMatchMode="exact">
    <f:facet name="filter">
        <p:inputText onkeyup="PF('dataTableUIWidget').filter();" converter="javax.faces.Long" class="ui-column-filter"/>
    </f:facet>
    <h:outputText value="#{row.discountId}"/>
</p:column>

discountId would be converted to Long by the specified converter. dataTableUIWidget is a widgetVar of <p:dataTable>.

In case of LazyDataModel<T>, the type of the Map of filters has been changed to Map<String, Object> (from Map<String, String>) both the overloaded versions of the load() method.

For single column sorting,

@Override
public List<Type> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
    return super.load(first, pageSize, sortField, sortOrder, filters);
}

and for multiple columns sorting.

@Override
public List<Type> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) {
    return super.load(first, pageSize, multiSortMeta, sortOrder, filters);
}

As for the example in the question, it can be rewritten something like the following.

<p:column id="discountStartDate" headerText="#{messages['discount.startdate']}" filterBy="#{row.discountStartDate}" sortBy="#{row.discountStartDate}" width="200" style="text-align: right;">

    <f:facet name="filter">
        <p:calendar id="filterStartDate" converter="#{dateTimeConverter}"
                    timeZone="Asia/Kolkata" locale="#{localeBean.locale}"
                    pattern="dd-MMM-yyyy hh:mm:ss a"
                    readonly="#{facesContext.currentPhaseId.ordinal eq 6}"
                    label="#{messages['discount.startdate']}"
                    effect="slide"
                    size="12"
                    onclick="PF('filterStartDateWidget').setDate(null);PF('dataTableUIWidget').filter();"
                    widgetVar="filterStartDateWidget"
                    showButtonPanel="true" navigator="true">

            <p:ajax event="dateSelect"
                    onstart="PF('dataTableUIWidget').filter();PF('blockDataTableUIWidget').block();"
                    oncomplete=" PF('blockDataTableUIWidget').unblock();"
                    onerror="alert('error');"/>
        </p:calendar>
    </f:facet>

    <p:cellEditor>
        <f:facet name="output">
            <h:outputText value="#{row.discountStartDate}" converter="#{dateTimeConverter}"/>
        </f:facet>
        <f:facet name="input">
            <p:tooltip for="dataTableTxtDiscountStartDate" value="#{messages['tooptip.dataTable.popup.calendar']}"/>
            <p:calendar id="dataTableTxtDiscountStartDate" binding="#{edStartDate}" value="#{row.discountStartDate}" converter="#{dateTimeConverter}" timeZone="Asia/Kolkata" locale="#{localeBean.locale}" pattern="dd-MMM-yyyy hh:mm:ss a" readonly="#{facesContext.currentPhaseId.ordinal eq 6}" label="#{messages['discount.startdate']}" effect="explode" required="true" showButtonPanel="true" navigator="true"/>
        </f:facet>
    </p:cellEditor>
</p:column>

dateTimeConverter is a type of org.joda.time.DateTime. Hence, the date passed through this filter will be available as org.joda.time.DateTime after just casting from Object taking it from the filter Map.

查看更多
登录 后发表回答