RichFaces – filtering with custom function

In my previous post, I have shown how to use built-in filtering in RichFaces. The basic filtering uses startsWith() method to filter. This is fine but you might have a situation where you need to write your own custom filtering method.

To keep things simple, let’s apply custom filtering to Name column only. For Location column we will keep the standard filtering.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<h:form>
   <rich:dataTable value="#{wondersBean.sevenNewWonders}" var="wonder"
      id="table">
      <rich:column filterMethod="#{wondersBean.filterWonders}">
         <f:facet name="header">
            Name
	     <h:panelGroup>
	        <h:outputText value="Name" />
		<br />
		<h:inputText value="#{wondersBean.filterValue}" id="input">
		   <a4j:support event="onkeyup" ignoreDupResponses="true"
			 requestDelay="700" reRender="table" focus="input" />
		</h:inputText>
	     </h:panelGroup>
	 </f:facet>
	 <h:outputText value="#{wonder.name}" />
      </rich:column>
      <rich:column filterBy="#{wonder.location}" filterEvent="onblur">
          <f:facet name="header">Location</f:facet>
	  <h:outputText value="#{wonder.location}" />
       </rich:column>
       <rich:column>
	   <f:facet name="header">Image</f:facet>
	   <h:graphicImage url="#{wonder.imageUrl}" />
       </rich:column>
   </rich:dataTable>
</h:form>

Most of the stuff happening inside the first rich:column tag starting at line #4. First I define the actual custom filtering method via filterMethod attribute. I will come back to is shortly. The rest is just an input field with a4j:support with onkeyup event. One the filtering is done, we return the focus to input field with focus attribute.

The changes to managed bean are minor. We have to add the filtering method and the filterValue property (this property holds the value we enter on the page).

...
private String filterValue = "";
// getter and setter method for filterValue
 
public boolean filterWonders(Object current) {
   Wonder currentWonder = (Wonder)current;
   if (filterValue.length()==0) {
      return true;
   }
   if (currentWonder.getName().startsWith(filterValue)) {
      return true;
   } 
   else {
	return false; 
   }
}
...

The method returns boolean value. The value entered from the page is checked against each value in the list. Value of true means include the current object in the filtering result. The filterWonders is not much different from using the built-in starsWith() method, however, you are free to add more interesting filtering in this method as you see fit. One thing different is that the method requires exact case. In other words, entering ‘A’ or ‘a’ is not the same. This is just to show you to get setup custom filtering.

An alternative approach is to use filterExpression instead of filterMethod. It basically works the same way. It has to evaluate to either true or false. true means the value is included in the filtering result.

<rich:column filterExpression="#{..}">
...
</rich:column>

43 comments

  1. Lei

    Do you know how to use the built-in order function after using this custom filtering function? Really appreciate it if you can help.

  2. Wahid

    Hi,
    when I used this customized filter-function in parallel with sorting-function, I noticed that once I clicked onto the inputText, the sorting get executed !!! How can I avoid this, and enabling sorting only through the sorting arrows?

    • max

      Try adding Event.stop(event) to the input:

      <h:inputText value="#{wondersBean.filterValue}" id="input" 
            onclick="Event.stop(event);">
         <a4j:support event="onkeyup" ignoreDupResponses="true"
      	  requestDelay="700" reRender="table" focus="input" />
      </h:inputText>
  3. Wahid

    Thanks max, it worked perfectly!
    My other wish, is how can I deactivate the “case-sensitivity” of this custom-filtering?
    For any suggestion I’m so thankful.

    Wahid

  4. Wahid

    Hi Max,
    my last question before I publish the page:
    How can I “reset the filter” every time when the user leaves the page with the filterable tabled (the filtered result remains saved) ?

  5. Wahid

    I could resolve it putting an:

    and in the bean I set up a resetFilter() Method, which simply set all the filter strings to “” !

    Now I have another column with timestamps (long values presented as “dd.MM.yyyy HH:mm:ss”), I tried to implement a and using a filterMethod, which has to compare the input(as date) and the long value(converted to date) but I failed !

  6. wahid

    Sorry for my humble english!! :-). I wanted simply to say in my last post, that I got the reset function to work.
    And what I am now in need of, is to filter a column with a rich:calendar, by selecting a day it’d will be able to filter out the values (timestamps : “dd.MM.yyyy HH:mm:ss”) according to the selected day (Input will be something like this “dd.MM.yyyy”) is it possible ?

    Thanks in advance

  7. Wahid

    @max: Unfortunately I could not realize filtering with a rich:calendar, any indication?
    @AllPostReader: did someone before make a custom filtering like I’d like to have?
    I’m struggling to get it work

  8. Wahid

    Hi max, well I tried to tinker the following code, but it’s still not working as wished:


    ….

    /rich:column>
    ….

    an in backend Bean:

    private Date timestampFilter = Calendar.getInstance().getTime();

    //Getter Setter

    ….
    public boolean filterTimestamp(Object current){

    History currentHist = (History) current;
    Date histDate = new Date(currentHist.getTimestamp());
    Calendar cal = Calendar.getInstance();

    cal.setTime(histDate);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    histDate = cal.getTime();

    cal.setTime(timestampFilter);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    timestampFilter = cal.getTime();

    if(currentHist != null){
    if (histDate.equals(timestampFilter)){
    return true;
    }else {
    return false;
    }
    }else {
    return false;
    }
    }

    The problem: When I select a day, the filter function is fired and the right result is listed, but strangely and after that the event is completed, I can no more get the Calendar popup by clicking on the input-field or on the button-icon !!!

    Any idea?

  9. Wahid

    Sorry the first part was removed from my post (WordPress filter?)!!!

    ….
    #
    #
    #
    #
    #
    # <rich:calendar datePattern="dd.MM.yyyy"
    #value="#{HistoryFilterBean.timestampFilter}" id="inputTimestamp"
    #
    #
    #
    #
    #
    #
    #
    #/rich:column>
    ….

  10. Wahid

    I hope it’d will be showed this time after commenting out..

    ….
    <!–

    <rich:calendar datePattern="dd.MM.yyyy"
    value="{HistoryFilterBean.timestampFilter}" id="inputTimestamp"

    /rich:column>–>
    ….

  11. Wahid

    Oups! my last attempt with tag....
    ...

    <!--

    <rich:calendar datePattern="dd.MM.yyyy"
    value="{HistoryFilterBean.timestampFilter}" id="inputTimestamp"

    /rich:column>-->

    ....

  12. Wahid

    <rich:calendar datePattern="dd.MM.yyyy"
    value="{HistoryFilterBean.timestampFilter}" id="inputTimestamp"

    /rich:column>

  13. max

    @Wahid: I don’t know what the problem is, I would need to reproduce the problem and unfortunately I don’t have time to do that. It would be much better if you post this on RichFaces forum. They are more people that monitor the forum and reply to questions. I hope you understand.

  14. Wahid

    Hi Max, unfortunately I was not able to post the jsp code block to show you the issue. But anyway thank you really for your useful post. If I’d find any solution to through RichFaces forum, I will post it here later.
    Regards

  15. Ben

    Is there a convenient way to get the filtered list? I want a button that will perform an action on all the items the user has displayed in the list.

  16. Wahid

    Hi Max,
    is it possible after filtering the columns to get “a reduced datamodel” back, which I used at the beginning to fill the rich:datatable ? I have too many columns in my datatable (61 columns), and I used the custom filterMethod to put a request delay and also to avoid quick user input.

  17. Jethro

    Max: great tip! I have one problem with it though: if I use this approach the arrow indicator for sorting appears next to the inputText instead of next to the outputLabel. I understand why this happens, because everything is now in the header. I tried to use a filter facet, but this does not render. Is there a reason why there is no filter facet for a rich:dataTable?

  18. Jethro

    @Max: yeah, I know there is not filter facet. I’m just wondering if there is a way to make the “sorting arrow” appear next to the label instead of next to the custom input field.

  19. Murali

    Hi Max,

    I have added a checkbox for in the table for selection of a row.
    When i click on the checkbox, i re-Render the checkbox id.

    When ever i click the check box, filter method is called.
    if i have 1000 records in table, filter method is called 1000 times.

    Is there any way to stop this, when i select the check box.

    Thanks
    Murali

  20. AT

    this is filtering on client side only and not existing list on server. Is there a way to filter the list as well.
    Problem I am having is that after filtering if I select a row and edit, it will edit first object in list.

  21. max

    @AT: if filtering is done by filterMethod=”#{wondersBean.filterWonders}” — that it’s server-side. Also notice that an Ajax request is sent to the server when input is entered.

  22. Pradip

    Hi,
    I have to show the count of filtered list item. Please suggest how can I get the count it?
    eg.
    Table list has 10 item. After user provided filter criteria in the text box… filtered item are 5 only and same is shown in the table.
    How can I get this count?

Leave a Reply