ICEfaces
  1. ICEfaces
  2. ICE-10811

ace:dataTable add support for ranged filtering

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 4.0
    • Fix Version/s: 4.1
    • Component/s: ACE-Components
    • Labels:
      None
    • Environment:
      Any
    • Assignee Priority:
      P1

      Description

      Add the ability to filter rows based on a range of values for a given column, so that all values within the specified minimum and maximum values are matched and rendered on the page. This would only apply to numerical and Date types.
      1. test.html
        1 kB
        Arturo Zambrano

        Issue Links

          Activity

          Hide
          Arturo Zambrano added a comment - - edited

          Committed improvement at revision 46074.

          As described in ICE-10446, the revised behaviour of this feature is as follows:

          • The user has the option of setting the 'type' attribute on the ace:column tag to declare the data type used in that column. The default value for this attribute is 'TEXT'. So, if the user doesn't set this attribute, things will continue to work normally as in previous versions. The supported types are TEXT, DATE, BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT and DOUBLE.
          • If the user desires to do the filtering based on a range of values, rather than a single value, they would have to set the 'filterRange' attribute to true, in the ace:column tag as well. The default value of this attribute would be false, so that things continue to work normally if it's not set.
          • If the user wants to programmatically change the minimum and maximum values for a range or if they want to give starting values to one or both of them, they would be able to do so by binding the corresponding data to the attributes 'filterValueMin' and 'filterValueMax'.
          • When using the DATE type, users can specify a Date pattern via the 'filterDatePattern' attribute, which works like the ace:dateTimEEntry's 'pattern' attribute. Likewise, a Locale can be specified via the 'filterDateLocale' attribute, which works in the same way as the ace:dateTimeEntry's 'locale'.
          • The data type for filtering purposes is only specified via the 'type' attribute. It is not deduced from the object type being processed. So, if the data type is actually Date or Double and the 'type' attribute is not set (or if it is explicitly set to 'text'), those values will be treated as strings, in order to preserve backwards compatibility. Only when a specific data type is specified through this attribute, the data will be treated differently for the purposes of filtering.
          • If only the minimum value is provided by the app developer, the rows whose value for that column is equal or greater than such minimum value will match the filter query.
          • If only the maximum value is provided by the app developer, the rows whose value for that column is equal or less than such maximum value will match the filter query.
          • The 'filterMatchMode' options only apply to TEXT types.
          • Global filtering is only applied to (non-range) TEXT types.
          • For the lazy mode, a new property 'columns' was added to LazyDataModel. The ace:dataTable will call setColumns(getColumns(true) before invoking the load method. App developers can access these column objects to obtain the minimum and maximum filter values when using range filtering.
          Show
          Arturo Zambrano added a comment - - edited Committed improvement at revision 46074. As described in ICE-10446 , the revised behaviour of this feature is as follows: The user has the option of setting the 'type' attribute on the ace:column tag to declare the data type used in that column. The default value for this attribute is 'TEXT'. So, if the user doesn't set this attribute, things will continue to work normally as in previous versions. The supported types are TEXT, DATE, BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT and DOUBLE. If the user desires to do the filtering based on a range of values, rather than a single value, they would have to set the 'filterRange' attribute to true, in the ace:column tag as well. The default value of this attribute would be false, so that things continue to work normally if it's not set. If the user wants to programmatically change the minimum and maximum values for a range or if they want to give starting values to one or both of them, they would be able to do so by binding the corresponding data to the attributes 'filterValueMin' and 'filterValueMax'. When using the DATE type, users can specify a Date pattern via the 'filterDatePattern' attribute, which works like the ace:dateTimEEntry's 'pattern' attribute. Likewise, a Locale can be specified via the 'filterDateLocale' attribute, which works in the same way as the ace:dateTimeEntry's 'locale'. The data type for filtering purposes is only specified via the 'type' attribute. It is not deduced from the object type being processed. So, if the data type is actually Date or Double and the 'type' attribute is not set (or if it is explicitly set to 'text'), those values will be treated as strings, in order to preserve backwards compatibility. Only when a specific data type is specified through this attribute, the data will be treated differently for the purposes of filtering. If only the minimum value is provided by the app developer, the rows whose value for that column is equal or greater than such minimum value will match the filter query. If only the maximum value is provided by the app developer, the rows whose value for that column is equal or less than such maximum value will match the filter query. The 'filterMatchMode' options only apply to TEXT types. Global filtering is only applied to (non-range) TEXT types. For the lazy mode, a new property 'columns' was added to LazyDataModel. The ace:dataTable will call setColumns(getColumns(true) before invoking the load method. App developers can access these column objects to obtain the minimum and maximum filter values when using range filtering.
          Hide
          Arturo Zambrano added a comment - - edited

          It was necessary to add the filterDatePattern and filterDateLocale for a number of reasons:

          • It's not possible to deduce a date patern from Date objects.
          • It wasn't possible to support f:convertDateTime, since what it does is to set the converter attribute of the parent component to a DateTimeConverter, based on the given parameters, and this only applies to UIInput descendants, and Column is not a UIInput descendant. It wasn't possible to parse the f:convertDateTime tag at render time either, because it is processed much earlier in the lifecycle and its values aren't accessible afterwards.
          • It wasn't possible to parse the tag as we can parse f:selectItem tags, because these are actually UISelectItem components, and there's no equivalent for f:convertDateTime.
          Show
          Arturo Zambrano added a comment - - edited It was necessary to add the filterDatePattern and filterDateLocale for a number of reasons: It's not possible to deduce a date patern from Date objects. It wasn't possible to support f:convertDateTime, since what it does is to set the converter attribute of the parent component to a DateTimeConverter, based on the given parameters, and this only applies to UIInput descendants, and Column is not a UIInput descendant. It wasn't possible to parse the f:convertDateTime tag at render time either, because it is processed much earlier in the lifecycle and its values aren't accessible afterwards. It wasn't possible to parse the tag as we can parse f:selectItem tags, because these are actually UISelectItem components, and there's no equivalent for f:convertDateTime.
          Hide
          Arturo Zambrano added a comment - - edited

          Another option for the Lazy Loading case, perhaps cleaner, would be to overload the load() method, adding another parameter, which contains the processed and converted minimum and maximum values for range filtering per column. We would implement this method with a trivial approach, so that existing applications don't need to implement it. It would be implemented in the following way, so that users can completely ignore it and keep things working as they were:

          // existing method
          public abstract List<T> load(int first, int pageSize, SortCriteria[] sortCriteria, Map<String,String> filters);
          
          // new method
          public List<T> load(int first, int pageSize, SortCriteria[] sortCriteria, Map<String,String> filters, Map<String, RangeFilterValues<Object,Object>>) {
          	return load(first, pageSize, sortCriteria, filters);
          }
          

          This way, developers interested in processing range filtering in the Lazy mode would override the second method with their own implementation, while developers who don't know about the new range filtering capabilities or who are just not interested in them can leave it as it is.

          Show
          Arturo Zambrano added a comment - - edited Another option for the Lazy Loading case, perhaps cleaner, would be to overload the load() method, adding another parameter, which contains the processed and converted minimum and maximum values for range filtering per column. We would implement this method with a trivial approach, so that existing applications don't need to implement it. It would be implemented in the following way, so that users can completely ignore it and keep things working as they were: // existing method public abstract List<T> load( int first, int pageSize, SortCriteria[] sortCriteria, Map< String , String > filters); // new method public List<T> load( int first, int pageSize, SortCriteria[] sortCriteria, Map< String , String > filters, Map< String , RangeFilterValues< Object , Object >>) { return load(first, pageSize, sortCriteria, filters); } This way, developers interested in processing range filtering in the Lazy mode would override the second method with their own implementation, while developers who don't know about the new range filtering capabilities or who are just not interested in them can leave it as it is.
          Hide
          Ken Fyten added a comment -

          Seems good, suggestion to change the "filterRange" attribute name on ace:column to "rangedFilter" to better match with the Boolean type.

          Show
          Ken Fyten added a comment - Seems good, suggestion to change the "filterRange" attribute name on ace:column to "rangedFilter" to better match with the Boolean type.
          Hide
          Arturo Zambrano added a comment -

          r46076: changed attribute name from 'filterRange' to 'rangeFilter'; modified lazy mode approach for range filtering; added special controls for boolean filter inputs; added fix to date filtering inputs to make the max date cover the entire number of seconds in that day, instead of just the first second; restricted input of number types to only allow numbers, the decimal point and the minus sign.

          Show
          Arturo Zambrano added a comment - r46076: changed attribute name from 'filterRange' to 'rangeFilter'; modified lazy mode approach for range filtering; added special controls for boolean filter inputs; added fix to date filtering inputs to make the max date cover the entire number of seconds in that day, instead of just the first second; restricted input of number types to only allow numbers, the decimal point and the minus sign.
          Hide
          Arturo Zambrano added a comment -

          r46080: added 'Filtering Dates' and 'Filtering Ranges' showcase demos.

          Show
          Arturo Zambrano added a comment - r46080: added 'Filtering Dates' and 'Filtering Ranges' showcase demos.
          Hide
          Arturo Zambrano added a comment -

          r46082: fixed input issues in number filter fields and removed ".0" at the end of the value for float and double types, unless an actual fraction is specified

          Show
          Arturo Zambrano added a comment - r46082: fixed input issues in number filter fields and removed ".0" at the end of the value for float and double types, unless an actual fraction is specified
          Hide
          Arturo Zambrano added a comment -

          r46098: fix for exception issue with boolean column type; fix for issue with not being able to clear filter values; fix for avoiding popping up the calendar right after clearing the value; fix to support other non-character keys in number filter fields like delete, arrows keys, etc.; changed spelling of attribute from rangeFilter to rangedFilter; change for not having to use all capital letters in the type attribute; fix to make the boolean menu start in an unset state instead of false; removed logging comments.

          Show
          Arturo Zambrano added a comment - r46098: fix for exception issue with boolean column type; fix for issue with not being able to clear filter values; fix for avoiding popping up the calendar right after clearing the value; fix to support other non-character keys in number filter fields like delete, arrows keys, etc.; changed spelling of attribute from rangeFilter to rangedFilter; change for not having to use all capital letters in the type attribute; fix to make the boolean menu start in an unset state instead of false; removed logging comments.
          Hide
          Arturo Zambrano added a comment -

          I modified the range filtering test page to use the LONG type instead of INT, since that's the type used in the MusicTrackInfo data object for the sales fields, but it still doesn't work. The ranged filtering showcase demo works as expected. It's still not clear why the page in the app isn't working, since there's not much difference between the two pages.

          Show
          Arturo Zambrano added a comment - I modified the range filtering test page to use the LONG type instead of INT, since that's the type used in the MusicTrackInfo data object for the sales fields, but it still doesn't work. The ranged filtering showcase demo works as expected. It's still not clear why the page in the app isn't working, since there's not much difference between the two pages.
          Hide
          Arturo Zambrano added a comment -

          r46117: fix to render option labels of the boolean as inner text instead of using the label attribute, in order to make labels visible on FF.

          Show
          Arturo Zambrano added a comment - r46117: fix to render option labels of the boolean as inner text instead of using the label attribute, in order to make labels visible on FF.
          Hide
          Arturo Zambrano added a comment - - edited

          As for the issue with the bottom border of the drop down list not being visible on Chrome, that's just an issue with Chrome itself. It seems to only happen when there's an odd number of option elements in the select menu. It doesn't happen when there are even numbers. I'm attaching a pure-HTML test case to show the issue. Unfortunately, there's no way to style the drop down list itself on Webkit.

          This seems to happen because the border is very thin, like only 1px wide, so it might disappear on screens that scale the resolution.

          Show
          Arturo Zambrano added a comment - - edited As for the issue with the bottom border of the drop down list not being visible on Chrome, that's just an issue with Chrome itself. It seems to only happen when there's an odd number of option elements in the select menu. It doesn't happen when there are even numbers. I'm attaching a pure-HTML test case to show the issue. Unfortunately, there's no way to style the drop down list itself on Webkit. This seems to happen because the border is very thin, like only 1px wide, so it might disappear on screens that scale the resolution.
          Hide
          Liana Munroe added a comment -

          Tested new showcase demos with ICEfaces 4 trunk r46124.
          ace:dataTable > Filtering Ranges demo
          This demo does not accept Number pad keyboard input into the Weight, MPG and Cost filter fields.
          ace:dataTable > Filtering Dates demo
          When manually typing a date then pressing ENTER, the date field is cleared.

          Show
          Liana Munroe added a comment - Tested new showcase demos with ICEfaces 4 trunk r46124. ace:dataTable > Filtering Ranges demo This demo does not accept Number pad keyboard input into the Weight, MPG and Cost filter fields. ace:dataTable > Filtering Dates demo When manually typing a date then pressing ENTER, the date field is cleared.
          Hide
          Arturo Zambrano added a comment -

          The reason why the range filtering test doesn't work on the QA test app is simply the use of the binding attribute in the ace:dataTable component. Removing this attribute makes things work as expected.

          Show
          Arturo Zambrano added a comment - The reason why the range filtering test doesn't work on the QA test app is simply the use of the binding attribute in the ace:dataTable component. Removing this attribute makes things work as expected.
          Hide
          Arturo Zambrano added a comment -

          r46184: added keycodes for the number pad keys; fix for allowing to submit a date by pressing enter; added the specified date pattern as an inField label so that users who want to type a date know which format to use

          Testing Notes: please test the two issues above.

          Also, in order to test the issues with using the ace:dataTable binding attribute when using filters, please also add a binding attribute to the other filter test and make sure that all the filter value attributes (filterValue, filterValueMin, filterValueMax) of every column are bound to a property in a bean.

          The reason why the plain filterTest works is because all the filter values are bound to a bean property, so the values don't disappear when typing a filter string. Please check if after these changes, the other filter tests work or fail.

          Show
          Arturo Zambrano added a comment - r46184: added keycodes for the number pad keys; fix for allowing to submit a date by pressing enter; added the specified date pattern as an inField label so that users who want to type a date know which format to use Testing Notes: please test the two issues above. Also, in order to test the issues with using the ace:dataTable binding attribute when using filters, please also add a binding attribute to the other filter test and make sure that all the filter value attributes (filterValue, filterValueMin, filterValueMax) of every column are bound to a property in a bean. The reason why the plain filterTest works is because all the filter values are bound to a bean property, so the values don't disappear when typing a filter string. Please check if after these changes, the other filter tests work or fail.
          Hide
          Arturo Zambrano added a comment -

          r46210: check for null before setting the min and max value filters, in order to avoid losing the submitted values

          Show
          Arturo Zambrano added a comment - r46210: check for null before setting the min and max value filters, in order to avoid losing the submitted values
          Hide
          Arturo Zambrano added a comment -

          r46214: fix for issue with not being able to clear the ranged filter fields; fix for including rows whose filter property is equal to the min or max filter values

          Show
          Arturo Zambrano added a comment - r46214: fix for issue with not being able to clear the ranged filter fields; fix for including rows whose filter property is equal to the min or max filter values
          Hide
          Liana Munroe added a comment -

          Tested with ICEfaces4 trunk r46220.
          JS error after using backspace in dateTimeEntry input field. Occurs with all browsers but it most easy to reproduce with Chrome.
          To reproduce:
          1.) Using Chrome browser go to showcase dataTable > Filtering Dates demo.
          2.) Insert cursor into the upper Event Date field.
          3.) Choose a date from the date picker then immediately insert the cursor at the end of the date shown in the field (as though you were to manually edit the date).
          4.) The date picker will be re-displayed. Instead of choosing a new date, press the backspace key until the field is cleared. The date picker will remain open.
          5.) Choose a new date. A js console error will appear.

          Uncaught TypeError: Cannot set property 'currentDay' of undefinedb.extend._selectDay @ ace-jquery-ui.js.jsf?ln=icefaces.ace&v=4_1_0_151113:296b.bind.selectDay @ ace-jquery-ui.js.jsf?ln=icefaces.ace&v=4_1_0_151113:312d.event.dispatch @ jquery.c.js.jsf?ln=icefaces.ace&v=4_1_0_151113:91l.handle @ jquery.c.js.jsf?ln=icefaces.ace&v=4_1_0_151113:85

          Show
          Liana Munroe added a comment - Tested with ICEfaces4 trunk r46220. JS error after using backspace in dateTimeEntry input field. Occurs with all browsers but it most easy to reproduce with Chrome. To reproduce: 1.) Using Chrome browser go to showcase dataTable > Filtering Dates demo. 2.) Insert cursor into the upper Event Date field. 3.) Choose a date from the date picker then immediately insert the cursor at the end of the date shown in the field (as though you were to manually edit the date). 4.) The date picker will be re-displayed. Instead of choosing a new date, press the backspace key until the field is cleared. The date picker will remain open. 5.) Choose a new date. A js console error will appear. Uncaught TypeError: Cannot set property 'currentDay' of undefinedb.extend._selectDay @ ace-jquery-ui.js.jsf?ln=icefaces.ace&v=4_1_0_151113:296b.bind.selectDay @ ace-jquery-ui.js.jsf?ln=icefaces.ace&v=4_1_0_151113:312d.event.dispatch @ jquery.c.js.jsf?ln=icefaces.ace&v=4_1_0_151113:91l.handle @ jquery.c.js.jsf?ln=icefaces.ace&v=4_1_0_151113:85
          Hide
          Arturo Zambrano added a comment -

          r46227: fix consisting of sending the filtering request from inside a timeout function and keeping a reference to such timeout function for clearing the timeout (and thus preventing the filtering request) when another filtering request is triggered within 200 milliseconds from the first one, in order to prevent javascript errors due to certain objects not found due to not having been set up yet.

          Show
          Arturo Zambrano added a comment - r46227: fix consisting of sending the filtering request from inside a timeout function and keeping a reference to such timeout function for clearing the timeout (and thus preventing the filtering request) when another filtering request is triggered within 200 milliseconds from the first one, in order to prevent javascript errors due to certain objects not found due to not having been set up yet.
          Hide
          Liana Munroe added a comment -

          Verified ICEfaces 4 trunk r46228, Tomcat 7, IE 11, 10, 9, 8, FF 34, Chrome 45. No longer able to reproduce console error with showcase dataTable > Filtering Dates demo or QA test apps.

          Show
          Liana Munroe added a comment - Verified ICEfaces 4 trunk r46228, Tomcat 7, IE 11, 10, 9, 8, FF 34, Chrome 45. No longer able to reproduce console error with showcase dataTable > Filtering Dates demo or QA test apps.
          Hide
          Arturo Zambrano added a comment -

          r46231: refactored fix for including dates that are exactly the specified minimum/maximum dates to make it work consistently

          Show
          Arturo Zambrano added a comment - r46231: refactored fix for including dates that are exactly the specified minimum/maximum dates to make it work consistently
          Hide
          Liana Munroe added a comment -

          Noticed a new issue that started after ICEfaces 4 trunk r46226. When clearing the dates in the Event Date fields in the showcase > Filtering Dates demo, the data does not un-filter and return to it's original state. When unfiltered there should be 99 rows. Before r46226 removing all filters would allow all data to display.

          Show
          Liana Munroe added a comment - Noticed a new issue that started after ICEfaces 4 trunk r46226. When clearing the dates in the Event Date fields in the showcase > Filtering Dates demo, the data does not un-filter and return to it's original state. When unfiltered there should be 99 rows. Before r46226 removing all filters would allow all data to display.
          Hide
          Arturo Zambrano added a comment -

          r46253: added a different way of detecting when the date filter fields are empty, since empty strings are not submitted in these cases, unlike the other filter types

          Show
          Arturo Zambrano added a comment - r46253: added a different way of detecting when the date filter fields are empty, since empty strings are not submitted in these cases, unlike the other filter types
          Hide
          Liana Munroe added a comment -

          Verified ICEfaces 4 trunk r46256. Tomcat 7, IE 11, 10 9, 8, FF 34, Chrome 45.

          Show
          Liana Munroe added a comment - Verified ICEfaces 4 trunk r46256. Tomcat 7, IE 11, 10 9, 8, FF 34, Chrome 45.
          Hide
          Carlo Guglielmin added a comment -

          If the user enters a higher minimum than maximum could we swap the values, or at least notify them? For example in the showcase you can enter minimum 5000 Weight and maximum 100 Weight and no results come up. Seems like it could be friendlier.

          Show
          Carlo Guglielmin added a comment - If the user enters a higher minimum than maximum could we swap the values, or at least notify them? For example in the showcase you can enter minimum 5000 Weight and maximum 100 Weight and no results come up. Seems like it could be friendlier.

            People

            • Assignee:
              Arturo Zambrano
              Reporter:
              Arturo Zambrano
            • Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: