question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Datatable: Filtering broken for including dynamic column multiple times

See original GitHub issue

1) Environment

  • PrimeFaces version: 8.0
  • Does it work on the newest released PrimeFaces version? Version? No
  • Does it work on the newest sources in GitHub? (Build by source -> https://github.com/primefaces/primefaces/wiki/Building-From-Source): Tried it but couldnt get my project to work as the whole page rendering was messed up
  • Application server + version: Tomcat 9.0.31
  • Affected browsers: Firefox, Chrome

2) Expected behavior

When filtering a column for a LocalDateTime as start date then all rows should stay in place which are after that date

3) Actual behavior

The filtering for the specific column does not work as filterValue in filterFunction is always null. It is actually null because that filterValue is actually the value from the next columns filter

4) Steps to reproduce

Write a dynamic column which you include 2 or more times. Then filter the first one and it should use the last columns value in filter for filtering

5) Sample XHTML

Included composition in table:

<p:dataTable id="clientDatatable"
                                     value="#{clientBean.entityList}"
                                     tableStyle="table-layout: auto"
                                     widgetVar="clientDatatableWidgetVar"
                                     var="client">
                            <f:facet name="header">
                                <h:outputText value="#{msg['title.clients']}"/>
                            </f:facet>
                            <p:column headerText="#{msg['generic.name']}"
                                      filterBy="#{client.name}"
                                      filterMatchMode="contains"
                                      sortBy="#{client.name}">
                                <h:outputText value="#{client.name}"/>
                            </p:column>
                            <ui:include src="../shared/timeColumnRangeFilter.xhtml">
                                <ui:param name="columnId" value="clientFirstSeenColumn"/>
                                <ui:param name="time" value="#{client.firstSeen}"/>
                                <ui:param name="headerMessageKey" value="#{msg['generic.firstSeen']}"/>
                                <ui:param name="datatableWidgetVar" value="clientDatatableWidgetVar"/>
                                <ui:param name="isColumnVisible" value="#{true}"/>
                                <ui:param name="isColumnExportable" value="#{true}"/>
                                <ui:param name="filterType" value="dateOnly"/>
                            </ui:include>
                            <ui:include src="../shared/timeColumnRangeFilter.xhtml">
                                <ui:param name="columnId" value="clientLastSeenColumn"/>
                                <ui:param name="time" value="#{client.lastSeen}"/>
                                <ui:param name="headerMessageKey" value="#{msg['generic.lastSeen']}"/>
                                <ui:param name="datatableWidgetVar" value="clientDatatableWidgetVar"/>
                                <ui:param name="isColumnVisible" value="#{true}"/>
                                <ui:param name="isColumnExportable" value="#{true}"/>
                                <ui:param name="filterType" value="dateOnly"/>
                            </ui:include>
                            <ui:include src="/pages/shared/clientStateColumn.xhtml">
                                <ui:param name="columnId" value="clientStateColumn"/>
                                <ui:param name="clientStatus" value="#{client.clientStatus}"/>
                                <ui:param name="headerMessageKey" value="ClientStatus"/>
                                <ui:param name="headerText" value="#{msg['ClientStatus']}"/>
                                <ui:param name="datatableWidgetVar" value="clientDatatableWidgetVar"/>
                                <ui:param name="isColumnVisible" value="#{true}"/>
                                <ui:param name="isColumnExportable" value="#{true}"/>
                            </ui:include>
</p:dataTable>

Actual column

<!-- filterType date only (Default) -->
    <c:if test="#{empty filterType or filterType eq 'dateOnly'}">
        <ui:param name="filterFunction" value="filterByDateRange"/>
        <ui:param name="pattern" value="dd.MM.yyyy"/>
    </c:if>
    <!-- filterType DateTime -->
    <c:if test="#{filterType eq 'dateTime'}">
        <ui:param name="filterFunction" value="filterByDateTimeRange"/>
        <ui:param name="pattern" value="dd.MM.yyyy HH:mm:ss"/>
    </c:if>
    <!-- filterType Time Only -->
    <c:if test="#{filterType eq 'timeOnly'}">
        <ui:param name="filterFunction" value="filterByTimeRange"/>
        <ui:param name="pattern" value="HH:mm:ss"/>
    </c:if>

    <p:column id="#{columnId}"
              filterBy="#{time}"
              sortBy="#{time}"
              exportFunction="#{columnExporter.panelGroupToOutputText}"
              filterFunction="#{filterController[filterFunction]}"
              filterMatchMode="contains" style="text-align: center; min-width: 170px"
              exportHeaderValue="#{headerMessageKey}"
              visible="#{isColumnVisible != null ? isColumnVisible : true}"
              exportable="#{isColumnExportable != null ? isColumnExportable : true}"
              toggleable="#{isColumnToggleable != null ? isColumnToggleable : true}">
        <f:facet name="header">
            <h:outputText value="#{headerMessageKey}"/>
            <p:watermark
                    value="#{filterType eq 'timeOnly' ? msg['placeholder.chooseTime'] : msg['placeholder.chooseDate'] }"
                    for="#{columnId}"/>
            <p:outputPanel style="text-align: center;">
                <h:outputText value="#{msg['generic.from']}"/>
                <p:calendar id="#{columnId}_from"
                            inputStyle="width: 105px"
                            widgetVar="#{columnId}_fromWidgetVar"
                            label="#{msg['generic.from']}"
                            navigator="true"
                            pattern="#{pattern}"
                            timeOnly="#{filterType eq 'timeOnly'}"
                            readonly="true"
                            showButtonPanel="true">
                    <p:ajax event="dateSelect"
                            global="false"
                            onstart="$(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_filter'), view).clientId}'))[0].value = $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_from'), view).clientId}_input'))[0].value + '-' + $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_to'), view).clientId}_input'))[0].value"
                            oncomplete="PF('#{datatableWidgetVar}').filter()"/>
                </p:calendar>
                <p:commandButton icon="fas fa-trash"
                                 ignoreAutoUpdate="true"
                                 global="false"
                                 title="#{msg['generic.reset']}"
                                 style="height: 25px; width: 25px; margin-left: 2px; top: 1px"
                                 onstart="PF('#{columnId}_fromWidgetVar').setDate(null); $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_filter'), view).clientId}'))[0].value = $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_from'), view).clientId}_input'))[0].value + '-' + $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_to'), view).clientId}_input'))[0].value;"
                                 oncomplete="PF('#{datatableWidgetVar}').filter()"/>
            </p:outputPanel>
            <p:outputPanel style="text-align: center;">
                <h:outputText value="#{msg['generic.till']} "/>
                <p:calendar id="#{columnId}_to"
                            inputStyle="width: 105px"
                            widgetVar="#{columnId}_toWidgetVar"
                            label="#{msg['generic.till']}"
                            navigator="true"
                            readonly="true"
                            timeOnly="#{filterType eq 'timeOnly'}"
                            showButtonPanel="true"
                            pattern="#{pattern}">
                    <p:ajax event="dateSelect"
                            global="false"
                            onstart="$(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_filter'), view).clientId}'))[0].value = $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_from'), view).clientId}_input'))[0].value + '-' + $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_to'), view).clientId}_input'))[0].value"
                            oncomplete="PF('#{datatableWidgetVar}').filter()"/>
                </p:calendar>
                <p:commandButton icon="fas fa-trash"
                                 title="#{msg['generic.reset']}"
                                 ignoreAutoUpdate="true"
                                 global="false"
                                 style="height: 25px; width: 25px; margin-left: 2px; top: 1px"
                                 onstart="PF('#{columnId}_toWidgetVar').setDate(null); $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_filter'), view).clientId}'))[0].value = $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_from'), view).clientId}_input'))[0].value + '-' + $(PrimeFaces.escapeClientId('#{p:resolveFirstComponentWithId(columnId.concat('_to'), view).clientId}_input'))[0].value"
                                 oncomplete="PF('#{datatableWidgetVar}').filter()"/>
            </p:outputPanel>
        </f:facet>
        <f:facet name="filter">
            <h:inputHidden id="#{columnId}_filter"/>
        </f:facet>
        <h:panelGroup id="timeRangeColumnPanelGroup#{columnId}"
                      styleClass="updatableColumnComponent">
            <h:outputText value="#{time}">
                <f:converter binding="#{localDateTimeConverter}"/>
                <f:attribute name="pattern" value="dd.MM.yyyy HH:mm:ss"/>
            </h:outputText>
        </h:panelGroup>
    </p:column>

6) Sample bean


7) Actual problem:

FilterFeature in Datatable changed from Primefaces 7.0 to 8.0.

In 7.0, the filter method was:

public void filter(FacesContext context, DataTable table, List<FilterMeta> filterMetadata, String globalFilterValue)

In 8.0 it is:

public void filter(FacesContext context, DataTable table, Map<String, FilterMeta> filterBy)

So the Map has the filterValue as Key which leads to the problem that 2 dynamic columns will result in the last one being added to the map and therefore filtering the wrong column.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
joergmattescommented, Mar 27, 2020

I have a similar problem. I am not using <p:column> directly, but always use a JSF custom tag (fullColumn.xhtml) which (among other things) includes filtering automatically by wrapping

<p:column filterBy="#{property}" ...>
  <h:outputText value="#{property}" />
</p:column>

As a result, the filterBy map has only one entry with key “property”, although there are many columns, which broke filtering after migrating to 8.0 But reading the PF code, I saw that FilterFeature.getFilterField() tries to use the column field attribute before falling back to resolving the filterByVE. Therefore, this solved the problem for me:

<p:column filterBy="#{property}" field="#{property}" ...>
  <h:outputText value="#{property}" />
</p:column>
0reactions
mellowarecommented, Aug 13, 2020

Closing this issue as the OP stated “But reading the PF code, I saw that FilterFeature.getFilterField() tries to use the column field attribute before falling back to resolving the filterByVE. Therefore, this solved the problem for me:” so using Column#field is the correct solution and closing ticket.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why can't I apply multi column filtering to a dynamically ...
I dynamically created another datatable and I added the footer to each column because I want to implement individual column filtering. I am ......
Read more >
Datatable filter not working - Stack Overflow
The problem is that the filtering is not working. Apparently it makes an ajax call which receives no answer an just keeps waiting....
Read more >
Problem Filter Data Table not working - Studio - UiPath Forum
Hi, I would like to generate a new table from an existing table that has to be filtered as follows, but these filters...
Read more >
Package 'data.table'
Finally, you can filter columns to include in .SD based on their names according to regular expressions via .SDcols=patterns(regex1, regex2, ...) ...
Read more >
Filtering Responses - Qualtrics
Filter that includes one of many selections from a multiple choice question ... In the image above, respondents could have selected Lower wait...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found