CompositeFilter

The CompositeFilter component allows user to build complex filter criteria with various filter conditions. It provides its own criteria API that can be easily adapted for different use-cases. There are two ready-to-use solutions for in memory filtering over collections and building Hibernate criteria. Also, CompositeFilter can be integrated with DataTable and TreeTable components and serve as an external filter in addition to column filtering options.


API Reference | Tag Reference
Online Demo

Key Features

Basic Configuration

The CompositeFilter component can be defined using the <o:compositeFilter> tag with a set of <o:filterProperty> tags inside. Each <o:filterProperty> tag defines one property that will be available to the user when building filter criteria. Here's a simple example:

<o:compositeFilter id="filter" value="#{CompositeFilterBean.criteria}">
    <o:filterProperty value="Artist" name="artist"/>
    <o:filterProperty value="Album" name="album"/>
    <o:filterProperty value="Kind" name="kind"/>
</o:compositeFilter>

The value attribute of <o:filterProperty> defines property title as it will be represented in property selector. The name attribute is used to specify property name and corresponds to name of the field in the data class or column name in the database.

Customizing Filter Type

The CompositeFilter component supports different types of filter properties. The type attribute of <o:filterProperty> tag defines which of the predefined filter types should be used. It can take the following values: "text", "number", "select", and "date". The default value is "text". The type determines a set of operations for the property and the kind of parameter editor.

Filter Type Operations Editor
"text" equals, contains, beginsWith, endsWith HtmlInputText
"number" equals, lessOrEqual, greaterOrEqual, less, greater, between Spinner
"select" equals DropDownField
"date" equals, lessOrEqual, greaterOrEqual, less, greater, between DateChooser

Customizing Editors

The <o:filterProperty> tag provides additional attributes for editor customizations:

Attribute Filter Type Description
converter all filter types The converter instance to be registered for this component
dataProvider text, select List of possible values list that will be displayed in drop down
maxValue number Maximum value for Spinner editor
minValue number Minimum value for Spinner editor
step number The amount by which the value is increased/decreased
timeZone date Time zone in which to interpret the time information in the date
pattern date Date pattern similar to that in the java.text.SimpleDateFormat class
caseSensitive text Whether search is case sensitive

Processing Filter Criteria

FilterCriterion class is designed to represent a model for the CompositeFilter component. The value attribute of the <o:compositeFilter> tag is used to the specify initial set of filter criteria and a value holder for the result of user's input. The CompositeFilter provides the following utility classes – PredicateBuilder for in memory filtering over collections and HibernateCriterionBuilder for building Hibernate criteria. The example below demostrates two ways of filtering using FilterCriterion.

<o:compositeFilter id="cf" value="#{CompositeFilterBean.criteria}" >
  <o:filterProperty name="firstName" value="First Name" type="text"/>
  <o:filterProperty value="age" type="number"/>
  <o:filterProperty name="dateOfBirth" value="Date Of Birth" type="date"
                    pattern="dd-MM-yyyy" timeZone="GMT"/>
  <o:filterProperty name="placeOfBirth.country" value="Country" type="select"
                    dataProvider="#{CompositeFilterBean.countries}"
                    converter="#{CompositeFilterBean.countryConverter}"/>
</o:compositeFilter>
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.hibernate.criterion.Criterion;
...
public class CompositeFilterBean {

   private List<User> customers;
   private List<User> filteredCustomers;
   private List<User> employees;
   private CompositeFilterCriterion criteria;

   ...

   public void setCriteria(CompositeFilterCriterion criteria) {
        this.criteria = criteria;

        Predicate predicate = PredicateBuilder.build(criteria);
        filteredCustomers = new ArrayList<User>(customers);
        CollectionUtils.filter(filteredCustomers, predicate);

	Criterion criterion = HibernateCriterionBuilder.build(criteria);
        employees = userService.findByCriterion(criterion);
        return result;
   }

   ...
}
public class UserService extends HibernateDaoSupport{

   public Collection<User> findByCriterion(Criterion criterion) {
        Criteria criteria = getSession().createCriteria(User.class);
        criteria.add(criterion);
        return (List<User>) criteria.list();
   }
}

Attaching to DataTable/TreeTable Components

The CompositeFilter component can be attached to the DataTable or TreeTable component using the for attribute of <o:compositeFilter> tag. This means that the data in the DataTable (or TreeTable) will be automatically filtered with criteria defined by user using the CompositeFilter. Furthermore the CompositeFilter will automatically detect table columns and provide them to a user as a basis for filters construction, which removes the need to specify the <o:filterProperty> tags when CompositeFilter is bound to a DataTable or TreeTable. This autodetection mode can be turned off by by assigning false to the autoDetect attribute (the default value is true), which makes it possible to customize the list of fields available for filtering or their parameters.

It's possible to attach CompositeFilter to a DataTable/TreeTable component even if that component already has other filters attached.

The example below shows two composite filter components attached to the same DataTable in both modes (with auto detection mode on and off). Both components will have the same appearance and behavior, and the same set of properties with the same types.

<o:compositeFilter id="filter1" for="banks"/>

<o:compositeFilter id="filter2" for="banks" autoDetect="false">
  <o:filterProperty name="institutionName" value="Institution Name" type="text"/>
  <o:filterProperty name="state" value="State" type="select"
                    dataProvider="#{StateList.values}" converter="#{StatesList.converter}"/>
  <o:filterProperty name="foundationDate" value="Founded" type="date">
     <f:convertDateTime pattern="MM/yyyy"/>
  </o:filterProperty>
</o:compositeFilter>

<o:dataTable id="banks" var="bank" value="#{BanksList.banks}">
  <o:column id="institutionName">
    <f:facet name="header">
      <h:outputText value="Institution Name"/>
    </f:facet>
    <h:outputText value="#{bank.institutionName}"/>
  </o:column>
  <o:column id="state" header="State">
    <h:outputText value="#{bank.state}" converter="#{StatesList.converter}"/>
  </o:column>
  <o:column id="foundationDate">
    <f:facet name="header">
      <h:outputText value="Founded"/>
    </f:facet>
    <h:outputText value="#{bank.foundationDate}">
      <f:convertDateTime pattern="MM/yyyy"/>
    </h:outputText>
  </o:column>
</o:dataTable>

When the CompositeFilter component is bound to a DataTable (or TreeTable) component, it displays the "Apply" button, which allows filtering the attached DataTable (or TreeTable). The text and appearance of this button can be customized by using the "applyButton" facet. You can place any UICommand component in this facet, for example <h:commandButton> or <h:commandLink> and configure their attributes according to your needs.

i18n Support

CompositeFilter provides ability to easily localize operation labels by specifying labels attribute <o:compositeFilter> tag and providing proper message bundle. The resource bundle should contain messages for each operation and have the following form:

org.openfaces.filter.condition.equals=Equals
org.openfaces.filter.condition.contains=Contains
org.openfaces.filter.condition.beginsWith=Begins with
org.openfaces.filter.condition.endsWith=Ends with
org.openfaces.filter.condition.lessOrEqual=<=
org.openfaces.filter.condition.greaterOrEqual=>=
org.openfaces.filter.condition.greater=>
org.openfaces.filter.condition.less=<
org.openfaces.filter.condition.between=Between
<o:loadBundle basename="com.mycompany.testapp.filter.MessageResources" var="messages"/>

<o:compositeFilter id="compositeFilter" value="#{CompositeFilterBean.criteria}" labels="#{messages}">
    <o:filterProperty name="title" value="Book Title" type="text"/>
    <o:filterProperty name="published" value="Date" type="date" pattern="yyyy"/>
</o:compositeFilter>

Client-Side API

All client-side API methods for the CompositeFilter component are listed below:

Method Description
add() Adds new filter row for CompositeFilter component on which this method is invoked.
remove(index) Removes filter row with specified index from CompositeFilter component on which this method is invoked.
clear() Removes all filter rows from CompositeFilter component on which this method is invoked.
OpenFaces