Divya
Divya

Reputation: 95

Using a custom global filter on p:dataTable

I am trying to implement a comma separated keyword search using global filter in PrimeFaces.

If user types in word1,word2 in the global search, all the rows which have word1 and word2 should be returned. As of now, I was not able to find a predefined multi word search functionality for global search in PrimeFaces. Global search only works with a single keyword. Eg: Search returns results only if user types either word1 or word2.

Seems like PrimeFaces uses client API filter() for global search. Is there a way to implement a search using multiple keywords?

<p:dataTable id="dwg" widgetVar="tblDwgDtl" var="dwgDtl" 
 value="#{dwgCtrlr.dwgs} sortMode="multiple" scrollable="true" 
 styleClass="bsa-drawing" rows="25" resizableColumns="true">
    <f:facet name="header">
        <p:panelGrid styleClass="ui-panelgrid-blank">
                <p:row>
                    <p:column colspan="6">
                        <p:inputText id="globalFilter" 
                        onkeyup="PF('tblDwgDtl').filter()" 
                        placeholder="#{msg['searchAllFields.text']}" />
                    </p:column>
                </p:row>
        </p:panelGrid>
   </f:facet>

Upvotes: 4

Views: 6511

Answers (1)

Jasper de Vries
Jasper de Vries

Reputation: 20158

PrimeFaces 8.0 and up

From PrimeFaces 8.0 you can use the globalFilterFunction attribute of the p:dataTable to implement your custom global filter. See https://primefaces.github.io/primefaces/8_0/#/components/datatable?id=filtering

Example use:

<p:dataTable ... globalFilterFunction="#{dtFilterView.globalFilterFunction}">
  ...
</p:dataTable>
public boolean globalFilterFunction(Object value, Object filter, Locale locale) {
  String filterText = (filter == null) ? null : filter.toString().trim().toLowerCase();
  if (filterText == null || filterText.equals("")) {
    return true;
  }
  int filterInt = getInteger(filterText);

  Car car = (Car) value;
  return car.getId().toLowerCase().contains(filterText)
          || car.getBrand().toLowerCase().contains(filterText)
          || car.getColor().toLowerCase().contains(filterText)
          || (car.isSold() ? "sold" : "sale").contains(filterText)
          || car.getYear() < filterInt
          || car.getPrice() < filterInt;
}

In your case of multiple words:

public boolean globalFilterFunction(Object rowValue, Object filter, Locale locale) {
  String filterText = (filter == null) ? null : filter.toString();
  if (filterText == null || filterText.isEmpty()) {
    return true;
  }
  return Stream.of(filterText.split(","))
          .allMatch(word -> singleWordFilter(value, word));
}

private boolean singleWordFilter(Object rowValue, String word) {
  // do your single word filtering logic
}

Before PrimeFaces 8.0

What you could do is replace the data table renderer with a custom one. Then, in there, replace the FilterFeature with a custom version. So, you would need extend the FilterFeature and take care of the multiple keywords there.

Upvotes: 6

Related Questions