Login required
Download

FilterPane Plugin

(18)
Author(s): Steve Krenek
Current Release: 0.7
Grails Version: 1.1.1 > *
Tags criteria filter search
To install the FilterPane plugin type this command from your project's root folder:
grails install-plugin filterpane

FilterPane Plugin

Help Grails be an active, open community! If you use this plugin and haven't rated it, please do so. If you've rated this plugin anything but 5 stars, please let me know why (See #Support for how). I'm striving to make this plugin the best that it can be, and constructive feedback is always appreciated.

This plugin adds filtering capabilities to any Grails application. The primary goals of this plugin include:

  • Easy integration with Grails list pages via custom tags
  • Smart operator display. Only practical filter operations are available for a property's data type. (e.g. no "like" operators for numeric properties)
  • Support for major operators including =, <>, >, <, >=, <=, like, ilike, between, is null, and is not null.
  • Smart filter value entry. Date properties display a date picker, boolean's display radio buttons, etc.
  • Support for a custom list of values, such as a filtering a text property with a constrained list of values.
  • Works with Grails list sorting out of the box with only minor modification to your list gsp.
  • Works with Grails pagination out of the box with only minor modification to your list gsp.
  • Honors domain constraints: nullable, blank, inList ( Since 0.4 )
Please note that you may experience duplicate rows if you use eager fetching. See http://jira.codehaus.org/browse/GRAILSPLUGINS-2063 for more information.

Index

Usage

The plugin is typically used in an application's list pages. To use the filters, make the following changes to your list.gsp pages. For a full list of tags and attributes, see the Reference section later in this document.

list.gsp

  1. Add the javascript and stylesheet includes to the head section of your page.
<filterpane:includes />

2. Somewhere in your page (typically near the bottom of the body tag), add the filter pane. This has the result of rendering a container div in your page.

<filterpane:filterPane domainBean="MyDomainClass" />

3. Add a button to invoke the filter pane somewhere on your list page. (Inside the pagination div works well on applications built from scaffolding.) A custom tag is provided to help create this button. The title attribute is optional. If omitted, the value of the button will be "Filter".

<filterpane:filterButton text="Whatever You Wish" />

If your application uses scriptaculous and you use the filterButton tag, the filter pane will fade in and out. Otherwise the filter pane simply appears and disappears.

Pagination

If you want to support pagination use something similar to the following:
<g:paginate total="${bookCount == null ? Book.count(): bookCount}" params="${filterParams}" />
In the example above, bookCount is any variable you pass into the controller's render model that contains the total number of records returned in your filtered data. Its value can be obtained from the filter service's count method. (See the controller section later in this document for more info.)
Note that you should not use Groovy's Elvis operator to test for bookCount's existence, as an empty set (count of 0) will return false, thus causing Book.count() to be used. See Groovy Truth for more info.

Also in the example above, filterParams is set in the model map of the render call in the controller. The value is a sub-map of the request params, and can be obtained by calling the "extractFilterParams" method on the included FilterUtils class. See the example below from the books example app.

render( view:'list', 
    model:[ bookList: filterService.filter( params, Book ), 
        bookCount: filterService.count( params, Book ), 
        filterParams: com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params), 
        params:params ] )

Starting with version 0.6 of the plugin, you can use the new paginate tag. The paginate tag wraps the Grails paginate tag and encapsulates the steps listed above. See the #paginate tag for more info.

List Sorting

If you want to support Grails's list sorting, you must add a the filter parameters to each Grails sortableColumn tag, as shown in the example below. It is not recommended to put the entire "params" map in here. Instead, it is recommended that you only include the FilterPane parameters, which is the same sub-map as is described in the Pagination section above.
<g:sortableColumn property="id" title="Id" params="${filterParams}" />

Controller

  1. Inject the filter service into your controller.
def filterService

2. Create the filter action in your controller.

def filter = {
    if(!params.max) params.max = 10
    render( view:'list', 
        model:[ domainClassList: filterService.filter( params, DomainClass ), 
        domainClassCount: filterService.count( params, DomainClass ), 
        filterParams: com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params), 
        params:params ] )
}

Where…

  • domainClassList is the name of the return list model the list action uses
  • DomainClass is the name of the domain class you are filtering
  • domainClassCount is the name of a variable that contains the total number of filtered results. This parameter is optional, but is useful if you want to use Grails pagination (which most of the time you will).
  • filterParams is a sub-map of the request parameters obtained via the FilterUtils.extractFilterParams method.
Keep in mind that you don't have to name the action "filter". You can name it anything you want, just remember to assign the same name to the filterPane tag's action attribute so your action gets called when applying the filter.

Examples

An example Grails application can be downloaded from http://svn.codehaus.org/grails-plugins/grails-filterpane/trunk/docs/examples/books.zip. It provides a tiny filterable book database that demonstrates the usage of the filterpane plugin.

Plugin Version History

DateVersionNotesKnown Compatible Grails Versions
2010-07-26_0.7Bug fixes.1.1.1 +
2010-03-24_0.6.8Bug fix for boolean 'false' value not working1.1.1 +
2010-03-23_0.6.7Some bug fixes and improvements to Grails-1.2.1 compatibility1.1.1 +
2010-02-17_0.6.6Should now work with Grails-1.2.1 and 1.1.11.1.1 +
2010-02-03_0.6.5Fixed several issues. See http://jira.codehaus.org/browse/GRAILSPLUGINS/fixforversion/160161.1.1 +
2009-11-17_0.6.4Added customForm attribute to filterPane tag. See docs for details in the reference section below.1.1.1
2009-10-27_0.6.3Fixed http://jira.codehaus.org/browse/GRAILSPLUGINS-16291.1.1
2009-09-13_0.6.2Child collection filtering fixed (GRAILSPLUGINS-1503). Filter service reworked to use Grails API instead of Groovy meta classes. Several integration tests added.1.1.1
2009-07-28_0.6.1Fixed a minor issue when rendering dropdowns for enums in associated properties.1.1.1
2009-07-27_0.6Completed several JIRA issues. See http://jira.codehaus.org/browse/GRAILSPLUGINS/fixforversion/15149 for details.1.1
2009-04-07_0.5Fixed JIRA issues 836, 988, and 1045. Form action is now POST. Entering in a filter value will now auto-select the first operator in its associated dropdown if none is selected (except for date properties). More info on issues at http://jira.codehaus.org/browse/GRAILSPLUGINS/fixforversion/151141.1
2009-03-22_0.4.3JIRA GRAILSPLUGINS-985 fixed.1.1
2009-03-22_0.4.2Now compatible with Grails 1.1. See JIRA GRAILSPLUGINS-9991.0.4, 1.1
2009-03-22_0.4.1Completed JIRAs GRAILSPLUGINS-822 and GRAILSPLUGINS-9031.0.4
2009-01-27_0.3.1Moved debug output to log.debug statements.1.0.4
2009-01-26_0.3Fixed packaging glitches. Updated example app.1.0.4
2009-01-25_0.2No major changes. Mainly code cleanup. Classes are now in packages, as per plugin specs.1.0.4
2009-01-16_0.1First release.1.0.4

Roadmap

  • Minor versions of 0.6 will address issues that arise with 0.6 and any critical bugs that are found.
  • Revised documentation that is more user friendly and improved examples of each feature.
  • Release 0.7 will focus on adding more unit and functional tests and simplifying the code base.
  • Future releases will be kept smaller than 0.5 and 0.6 in an attempt to deliver changes faster.

Support

  • For support questions, please use the Grails user mailing list (user@grails.codehaus.org), and include the word "filterpane" somewhere in your message.
  • JIRA issues may be found here.

Reference

The reference section is only applicable to versions 0.4 and above. Version 0.4 addressed some redundancy in the tag and attribute names provided by the plugin. While all previous attribute names are still supported, it is recommended to use those documented below instead. The deprecated tag and attribute names may be removed in the future.

Data Types and their Available Filter Operators

Text

(String, char)
OperatorSelect Option Display Text
ILikeContains
Not ILikeDoes Not Contain
LikeContains (Case Sensitive)
Not LikeDoes Not Contain (Case Sensitive)
"="Equal To
<>Not Equal To
Is NullIs Null
Is Not NullIs Not Null

Numeric

(Integer, Long, Short, Float, Double, BigDecimal, BigInteger)
OperatorSelect Option Display Text
"="Equal To
<>Not Equal To
<Less Than
<=Less Than or Equal To
>Greater Than
>=Greater Than or Equal To
BetweenBetween
Is NullIs Null
Is Not NullIs Not Null

Date

OperatorSelect Option Display Text
"="Equal To
<>Not Equal To
<Less Than
<=Less Than or Equal To
>Greater Than
>=Greater Than or Equal To
BetweenBetween
Is NullIs Null
Is Not NullIs Not Null

Boolean

OperatorSelect Option Display Text
"="Equal To
<>Not Equal To
Is NullIs Null
Is Not NullIs Not Null

Enum

(since 0.6)
OperatorSelect Option Display Text
"="Equal To
<>Not Equal To

Domain Constraint Modifications

If a property is not nullable (constraint nullable="false"), the Is Null and Is Not Null operators will not be available for that property.

Tags

includes

The includes tag should be used in the head section of your pages. It includes the necessary stylesheet and javascript file for the plugin. There are no attributes for this tag.

currentCriteria

This tag renders an unordered list of the currently applied filter criteria, along with links to remove individual filter criteria.
Attribute NameRequiredDefault ValueDescription
domainBeanYesThe domain bean being filtered. May be a String (e.g. "Book") or a class instance (e.g. ${Book})
idNofilterPaneCurrentCriteriaThe id of the unordered list.
titleNoNoneThe title attribute for the unordered list.
classNoNoneThe CSS class to apply to the list.
styleNoNoneThe style attribute for the list.
dateFormatNoyyyy-MM-dd HH:mm:ssThe format to apply when displaying date criteria.
actionNofilterThe controller action to submit to when removing criteria. Set this to the same as your filterPane tag's action attribute.
removeImgDirNoNoneThe directory the remove image file is located in.
removeImgFileNoNoneThe image filename to be used for the remove link. Note that if either removeImgDir or removeImgFile are missing, the text "(X)" will be used for the remove link.

filterButton

This tag renders an HTML link that shows the filter pane when clicked. When one or more filters are applied, this button will have the filter-applied css class.
Attribute NameRequiredDefault ValueDescription
textNo"Filter"The text that is displayed on the button.
appliedTextNo"Change Filter"The text displayed on the button when one or more filters are applied.
idNo"filterpane"The id of the html element.
textKeyNo"fp.tag.filterButton.text"The message bundle key that contains the text of this button. (i18n)
appliedTextKeyNo"fp.tag.filterButton.appliedText"The message bundle key that contains the applied text of this button. (i18n)

filterPane

This tag generates the filter pane itself. As of release 0.4, this tag pulls as much filtering information from the domain class as possible by default. All attributes from 0.3.1 are still supported, but are considered deprecated in favor of more sensible alternatives.
Attribute NameRequiredDefault ValueDescription
domainBeanYesNoneThe name of the Grails domain class to be filtered. This can either be a string (e.g. "Book"), or an actual class instance (e.g. "${Book}")
titleNo"Filter"The title text that is displayed at the top of the filter pane.
titleKeyNoNoneA message bundle key for looking up title text. (i18n)
idNo"filterpane"The id of the container div that holds the filter pane.
classNoNoneThe class attribute to add to the container div that holds the filter pane.
styleNoNoneThe style attribute to add to the container div that holds the filter pane.
formNameNo"filterForm"The name of the filter form element. Useful if you will use custom javascript on the form.
filterPropertiesNoNoneIf specified then no default properties are included, only those specified.
associatedPropertiesNoNoneUse this if you wish to filter any properties of associated domain objects (e.g. author.lastName). The value may either be a comma-delimited string, or a List of strings.
additionalPropertiesNoNoneBy default, identifier, version, and lastUpdated properties are not available to filter by. Use this attribute to allow them to be filtered. The value may either be a comma-delimited string, or a List of strings. Valid values are "id", "identifier", "version", and "lastUpdated"
excludePropertiesNoNoneBy default all persistent properties of the domain object are filterable. If you wish to exclude any properties from filtering, specify them in this attribute. The value may either be a comma-delimited string, or a List of strings.
actionNo"filter"The controller action to call when the filter is applied.
filterPropertyValuesNoNoneA map of property values to pass through to each property's value form control. For example, since Date properties render a date picker control, you could pass the following to limit the years in the date picker:
filterPropertyValues="${[someDateProperty:[years:2015..1999]]}"
or get the values from the database:
filterPropertyValues="${['author.lastName':[values:Author.executeQuery('select t.lastName from Author t')], 'readPriority.name':[values:ReadPriority.list()]]}"
customFormNofalseIf true or "true", the tag will not render the surrounding form or the "Apply" button on it. This is left to the developer. This attribute is useful if you want to embed the filterpane form in an existing form. (since 0.6.4) See the example below:
<form id="author-form" name="author-form" method="post">
	 <filterpane:filterPane id="author-filter-pane" domainBean="com.zeddware.grails.plugins.filterpane.Author"
            associatedProperties="books.title, books.bookType"
            titleKey="fp.tag.filterPane.titleText" customForm="true"
	    formName="author-form"/>
	<g:actionSubmit value="Apply Filter From Outside Filter Pane" action="filterCustomForm" />
</form>

isFiltered

This is a logical tag that will render its body if any filters are applied.
Attribute NameRequredDefault ValueDescription
(None)   

isNotFiltered

This is a logical tag that will render its body if no filters are applied.
Attribute NameRequredDefault ValueDescription
(None)   

paginate

This is a convenience tag that may be used in place of the grails paginate tag. It encapsulates adding the appropriate parameters to the grails paginate tag for the developer.
Attribute NameRequiredDefault ValueDescription
totalYesNoneA numeric total to be used when calculating pages. This is the same total that is passed to the Grails paginate tag.
domainBeanYes, if total's value is nullNoneIf total's value is null, this tag is used to perform a count for the user and pass that to the Grails paginate tag. If not specified and total's value is null, 0 will be used as the total count.

Internationalization (i18n)

The following keys are supported in message bundles for internationalizing the text in the plugin.

Filter Operators

  • fp.op.ILike
  • fp.op.NotILike
  • fp.op.Like
  • fp.op.NotLike
  • fp.op.Equal
  • fp.op.NotEqual
  • fp.op.IsNull
  • fp.op.IsNotNull
  • fp.op.GreaterThan
  • fp.op.GreaterThanEquals
  • fp.op.LessThan
  • fp.op.LessThanEquals
  • fp.op.Between

Property Name Display

By default, each property's natural name is displayed . To override this, use keys of the form: fp.property.text.propertyName , where propertyname is the domain property name. For associated properties, use keys of the form: fp.property.text.associatedBean.propertyName .

Filter Button Tag

If no textKey or appliedTextKey attributes are given, the default keys are checked.
  • fp.tag.filterButton.text
  • fp.tag.filterButton.appliedText

Filter Pane Tag

The filterPane tag's keys are listed below, along with their default values for clarity.
  • fp.tag.filterPane.titleText=Filter
  • fp.tag.filterPane.property.boolean.true=Yes
  • fp.tag.filterPane.property.boolean.false=No
  • fp.tag.filterPane.property.betweenValueSeparatorText=and
  • fp.tag.filterPane.sort.orderByText=Order by
  • fp.tag.filterPane.sort.noSelection.text=Select a Property
  • fp.tag.filterPane.sort.ascending=Ascending
  • fp.tag.filterPane.sort.descending=Descending
  • fp.tag.filterPane.button.cancel.text=Cancel
  • fp.tag.filterPane.button.clear.text=Clear
  • fp.tag.filterPane.button.apply.text=Apply
The full default message bundle can be found in the installed plugin's folder in the messages-filterpane.properties file.

The plugin supports the i18n Templates plugin's domain property format:

<domainClass>.<property> <-- for each property
FAQ

The previous text found here has been moved to a JIRA entry, and may be viewed here.

Q: A:

Sample Screenshot from Demo Application