A customer asked me recently whether the ColumnChooser plugin for our React Grid could be customized to include a search box. A quick check of the documentation showed some properties on the component that accept building block components for individual parts.
On that basis, I built a sample. You can check it out here:
The implementation in the file SearchableColumnChooser.js
has three parts. Starting from the bottom, you can see the component body implemented like this:
<form style={styles}><FormGroup controlId="searchText"><ControlLabel>Search</ControlLabel><FormControl type="text" value={filter} placeholder="Column Title" onChange={e => setFilter(e.target.value)} /></FormGroup><ColumnChooser.Container>{filteredChildren}</ColumnChooser.Container></form>
The form
is implemented using React Bootstrap elements, and it includes the standard rendering of the ColumnChooser.Container
plugin component, with a filtered list of children.
The second part of the implementation is a call to the recompose compose
helper and the withState
and withPropsOnChange
HOC (that’s Higher Order Component) functions.
const SearchableColumnChooser = compose( withState('filter', 'setFilter', ''), withPropsOnChange(['children', 'filter'], ({ children, filter }) => ({ filteredChildren: children.filter(c => childMatches(c, filter)) })) )(...);
withState
introduces a state field called filter
and a corresponding setFilter
function. You can see both these values in use in the component rendering above - no surprises there.
withPropsOnChange
creates a prop for the component that depends on the existing props children
(that’s the standard React thing) and filter
(the one created just before by withState
), and is re-created when either of these props changes. filteredChildren
is the name of the new property, it is created as a filtered list of based upon the original children, and it is eventually rendered into the ColumnChooser.Container
component.
The third part of the implementation is the predicate function used to filter the child nodes:
const childMatches = (child, filter) => child.props.item.column.title.toLowerCase().includes(filter.toLowerCase());
The function implements a simple case-insensitive search for the filter string entered by the end user.
The final bit required for the demo functionality is the line in index.js
where the ColumnChooser
is created. The newly created container component is passed as a property here:
<ColumnChooser containerComponent={SearchableColumnChooser} />
That’s it - try it! When you bring up the column chooser via the button in the top-right corner of the grid, it shows the search box. Enter a string and see the column list filtered down.
Please feel free to comment if you have any questions or ideas!