The In Filter is a special Column Filter that shows distinct Column Values
It is available in both the Filter Bar and the Filter Form
Each distinct value in the Column is displayed with a checkbox alongside it for selection
Developers have great flexibility in populating and rendering this list
AdapTable provides an In (and associated NotIn) Predicate to enable filtering on multiple column values.
Hint
This Predicate is selected by choosing the In Filter option in the Filter Predicates dropdown
When this is selected AdapTable's Filter Components display a list of all distinct items in the Column, together with an associated Checkbox indicating whether that value should be included in the Filter.
AdapTable provides developers with flexible, fine-grained control over each distinct Column value.
Custom Column Values
By default, AdapTable populates the In Filter dropdown by looping through all the values in AG Grid for the column, retrieving and then displaying the distinct items.
Note
AdapTable will ignore case sensitivity by default, e.g. will return "EUR" and "eur" as 2 separate items
This can be changed by setting the caseSensitivePredicates property in Predicate Options to true
Alternatively, developers can supply bespoke values to be displayed instead.
This is done by using the customInFilterValues property in Filter Options which allows extremely flexible and fine-grained control over which values are displayed and how they are rendered.
Caution
However this flexibilty can come with a potential performance cost, especially in Grids with large data sets
Use with care when displaying or counting visible values, when Row Grouping is active - see below for more details
The customInFilterValues property also populates the In predicate in the Query Builder (used by Grid Filter).
Note
This property is the equivalent of the filterValueGetterused by AG Grid's Set Filter, but which AdapTable ignores
Zero-based index of the first value to return. Reset to 0 when the dropdown opens or currentSearchValue changes. Increased when loading the next page (hasMore is true on the return object - this means lazy pagination is enabled).
When true, scrolling near the end of the list re-invokes customInFilterValues with a larger offset. New values are appended (same search). Search changes reset the list and set offset back to 0.
(params: { selectedValues:InFilterValue[]; selectedCount: number }) => string
Custom text for the collapsed IN Filter input. Receives the currently selected items (and their count) and must return a string so it works in React, Angular, Vue and vanilla. When omitted, the input shows the selected count (e.g. (3)) followed by the selected labels joined with a comma. When provided, it fully replaces that text (including the count - render one yourself if you want it).
This demo only lists values in In filter which are currently in the Grid (i.e. in filtered rows)
It also provides a count for each item
Try It Out
Click on the Language Column IN Filter to open the dropdown list of values
Note: (1) HTML does not appear as its not present in the (filtered) grid; (2) we see 9 and 11 as the 2 counts (matching the 11 currently filtered rows)
By default the values are listed in the order they appear in the Grid's DataSource.
But the function's context also contains a SortedValues property which will display values using any currently active Column Sorts (including Custom Sorts).
Note
This is not the same as using Column's current values' order (see below how to do that)
Hint
If there are multiple columns sorted, only the first column will display items in the same order as in the Grid
Other sorted Columns will display values according to the "natural" Sort Order (which may be different to the Grid)
Note: Because Name is the first sorted column it displays in same order as Grid; the other 2 columns show the sort order as if they were the first sorted column
As noted above, by default the values in the list are displayed in the order they appear in the Grid's DataSource, and we provide a SortedValues property which will leverage any currently active Column Sorts.
There is also an option to display values in the same order as they are currently displayed in the Grid.
This is done using the OrderedValues property, which will provide the order for any column (irrespective of whether it is currently sorted)
This demo shows the In Filter displaying values based on their Current Order
The Name column has a Column Sort - and the In filter list reflects that order
However other Columns (e.g. Issue Change and Github Watchers) display their current order (even though they are not sorted)
Try It Out
Change the Name column from an ascending to descending sort, and note how Issue Change and Github Watchers columns show their current (i.e. changed) order
This demo shows how to include System Predicates in the In Filter's list of values:
The Issue Change column adds 2 System Predicates: Positive and Negative
The Blanks and NonBlanks System Predicates are added to any column which contains empty values (e.g. Created or License) - with custom labels ("Empty" and "Not Empty") applied
import{AdaptableOptions,CustomInFilterValuesContext,InFilterValueInfo,}from'@adaptabletools/adaptable';import{WebFramework}from'./rowData';exportconstadaptableOptions: AdaptableOptions<WebFramework> = {primaryKey:'id',adaptableId:'In Filter Adding System Predicates',predicateOptions:{},filterOptions:{customInFilterValues:(context: CustomInFilterValuesContext)=>{letreturnValues: InFilterValueInfo[] = [];constblanks = ['',null,undefined];// Add Positive & Negative System Predicates for Issue Change Columnif(context.column.columnId === 'week_issue_change'){returnValues = [{label:'Positive',value:'Positive',},{label:'Negative',value:'Negative',},...context.defaultValues,];}// Add Blanks System Predicate for any Column which contains empty valueselseif(context.defaultValues.some((item: InFilterValueInfo)=>blanks.includes(item.value))){returnValues = [{label:'Empty',value:'Blanks',},{label:'Not Empty',value:'NonBlanks',},...context.defaultValues,];}// Return default list for all other columnselsereturnValues = context.defaultValues;return{values:returnValues};},columnFilterOptions:{defaultTextColumnFilter:'In',defaultNumericColumnFilter:'In',defaultDateColumnFilter:'In',},},initialState:{Dashboard:{ModuleButtons:['ColumnFilter','SettingsPanel'],},StatusBar:{StatusBars:[{Key:'Center Panel',StatusBarPanels:['Layout','ColumnFilter'],},],},Theme:{CurrentTheme:'dark'},Layout:{CurrentLayout:'Standard Layout',Layouts:[{TableColumns:['name','language','week_issue_change','github_stars','created_at','pushed_at','license','open_pr_count','closed_issues_count','closed_pr_count','has_projects','has_pages','updated_at','topics',],Name:'Standard Layout',AutoSizeColumns:true,},],},},};
Read-only
Loading demo…
Additionally the In Filter can display user-defined Custom Predicates.
In this example we have set all Date Columns to show the In Filter by default
We have provided a function implementation for the evaluateInPredicateUsingTime property in Predicate Options which returns true only for the Created column
We have also decided to show not to display the Tree, and instead show a list of distinct values, for the Updated column
Try It Out
Open the In Filter for the Created Column and navigate to 3 April 2009: note that 3 different time values are displayed, each of which can be selected separately
Open the In Filter for the Pushed Column and navigate to 19 May 2020: note that no different time values are displayed, but selecting that date results in 3 rows being displayed in the Grid
Open the In Filter for the Updated Column and note that you see a list of values rather than the Tree
import{AdaptableColumnContext,AdaptableOptions,CustomInFilterValuesContext,InFilterValueInfo,}from'@adaptabletools/adaptable';import{WebFramework}from'./rowData';exportconstadaptableOptions: AdaptableOptions<WebFramework> = {primaryKey:'id',adaptableId:'In Filter Date Columns',predicateOptions:{evaluateInPredicateUsingTime:(context: AdaptableColumnContext)=>{returncontext.column.columnId == 'created_at';},},filterOptions:{columnFilterOptions:{defaultDateColumnFilter:'In',},customInFilterValues:(context: CustomInFilterValuesContext)=>{if(context.column.columnId === 'updated_at'){return{values:context.orderedValues};}return{values:context.defaultValues};},},initialState:{Dashboard:{ModuleButtons:['ColumnFilter','SettingsPanel'],},StatusBar:{StatusBars:[{Key:'Center Panel',StatusBarPanels:['Layout','ColumnFilter'],},],},Theme:{CurrentTheme:'dark'},FormatColumn:{FormatColumns:[{Name:'formatColumn-date',Scope:{DataTypes:['date'],},DisplayFormat:{Formatter:'DateFormatter',Options:{Pattern:'MMM do yyyy, hh:mm:ss',},},},],},Layout:{CurrentLayout:'Standard Layout',Layouts:[{TableColumns:['name','language','created_at','github_stars','pushed_at','open_pr_count','updated_at','closed_issues_count','closed_pr_count','has_projects','has_pages','week_issue_change','topics',],Name:'Standard Layout',AutoSizeColumns:true,},],},},};
Read-only
Loading demo…
Suppressing Results Search
AdapTable automatically filters the displayed results in response to the user typing in the In Filter's search bar.
In other words typing 'b' will result in only values being displayed that contain 'b'.
This behaviour can be turned off so that AdapTable will do nothing if the user enters search text.
The In Filter is very powerful and offers great flexibility for users, enabling a huge range of use cases as can be seen above.
However this flexibility can come with a potential performance cost, especially in Grids with large data sets.
Caution
Use the customInFilterValues function with great care particularly in Columns with high numbers of distinct values
The following properties, in particular, can cause peformance issues if not used carefully:
visible and visibleCount - in both cases, each distinct value needs to be evaluated individually, which is particularly expensive when Row Grouping is active
orderedValues can be a very timely operation
Hint
AdapTable evaluates all these properties lazily (to ensure performance penalties are restricted to their actual use)
In other words, these properties are only evaluated if they are expressly invoked in the function implementation
Lazy Pagination
When a Column has a very large number of distinct values (or the list is fetched from a server), returning the full list in one go can be expensive and timely.
For this reason, AdapTable supports lazy pagination of the In Filter value list.
This is enabled by passing hasMore on the return InFilterValueResult object.
It this property is true, scrolling near the end of the list re-invokes customInFilterValues with a larger offset, and the new values are appended.
In addition, AdapTable calls the filterOptions.customInFilterValues with these useful properties:
offset - resets to 0 when the dropdown opens or currentSearchValue changes
limit - allows users to control the page size (default value is 1000)
selectedValues - the values currently selected in the In Filter (InFilterValue[]), including items that are not in the current page
AdapTable keeps the current selection when a new search page no longer includes previously selected items. Use selectedValues if you need those items in your own paging or labelling logic.
Hint
Combine lazy pagination with skipDefaultSearch: true when searching / paging is handled on the server
The Name Column's In Filter pages context.defaultValues (5 items per page) and sets hasMore until the list is exhausted. You can use a server request in this function to actually fetch the values paginated from a remote location.
Scrolling near the end of the dropdown loads the next page (appended to the existing values)
Search uses currentSearchValue with skipDefaultSearch: true and resets paging from offset 0
Try It Out
Open the Name Column In Filter and scroll to the bottom of the list to load more values. When a page is loaded, if the dropdown still has space, it will load additional pages until it fill the dropdown available size.
Type in the search box to filter the paged list (paging restarts from the first page)
To improve performance further, AdapTable caches each filter result, and then makes that available the next time the Column's In Filter is displayed, via the previousFilterResult property.
Note
AdapTable will destroy the cache if relevant things change (e.g. the column's data updates or a new sort is applied)
This allows you to first check if there is a cached result, and if there is, to display that.
Manually Applying Filters
Another option when using the In Filter with columns with a large numbers of records, is to turn on manually applying Column Filters.
When this property is set, the Filter is only evaluated when an Apply button is clicked, avoiding the list needing to be re-rendered on each click.
This contains 100,000 rows and 20 columns (the data is sourced externally so takes 5-8 seconds to fetch and load)
We have set the default Column Predicate to In for text, numeric and date columns
We have provided an "expensive" implementation of visible count (ie. we only list currently visible items together with a count)
However we first check to see if the values for the column are cached, and use that if they are
Finally we set manuallyApplyColumnFilter to true (for all columns) so that we only evaluate the Filter when the Apply button is clicked
import{AdaptableOptions,CustomInFilterValuesContext,InFilterValueInfo,}from'@adaptabletools/adaptable';import{WebFramework}from'./rowData';exportconstadaptableOptions: AdaptableOptions<WebFramework> = {primaryKey:'id',adaptableId:'In Filter Performance',filterOptions:{customInFilterValues:(context: CustomInFilterValuesContext)=>{// if previous result is cached, then display thatif(context.previousFilterResult){returncontext.previousFilterResult;}// show visible values only with count (the most expensive operation)return{values:context.defaultValues
.filter((info: InFilterValueInfo)=>info.visible)
.map(info=>{return{value:info.value,label:`${info.label} (${info.visibleCount})`,};}),};},columnFilterOptions:{manuallyApplyColumnFilter:true,defaultTextColumnFilter:'In',defaultNumericColumnFilter:'In',defaultDateColumnFilter:'In',},},initialState:{Dashboard:{ModuleButtons:['SettingsPanel'],PinnedToolbars:['Layout'],},Theme:{CurrentTheme:'dark'},Layout:{CurrentLayout:'Table Layout',Layouts:[{Name:'Table Layout',TableColumns:['id','prodName','company','price','amount','currency','orderDate','dueDate','lastName','firstName','origin','toAddress','invoiceNum','accountNum','department',],AutoSizeColumns:true,},{Name:'Grouped Layout',TableColumns:['id','company','price','amount','currency','orderDate','dueDate','lastName','firstName','origin','toAddress','invoiceNum','accountNum','department',],AutoSizeColumns:true,RowGroupedColumns:['prodName'],},],},},};