Oh my goodness - this took way longer than I'd like to admit. The Searchtabular NPM module creates a Table Component in React that can be searched. Seems simple enough. They even have a pretty detailed example. The problem I had is in the example the searchable table rows are being populated through the state object. I wanted the component to receive my row data through a prop - passed from a parent. This seemed pretty straight forward, but it did give me some headache.
import React from 'react'; import { compose } from 'redux'; import * as Table from 'reactabular-table'; import * as resolve from 'table-resolver'; import * as search from 'searchtabular'; class HighlightTable extends React.Component { constructor(props) { super(props); this.state = { searchColumn: 'all', query: {}, columns: [ { header: { label: 'Name' }, children: [ { property: 'name.first', header: { label: 'First Name' }, cell: { formatters: [search.highlightCell] } }, { property: 'name.last', header: { label: 'Last Name' }, cell: { formatters: [search.highlightCell] } } ] }, { property: 'age', header: { label: 'Age' }, cell: { formatters: [search.highlightCell] } } ], rows: [ { id: 100, name: { first: 'Adam', last: 'West' }, age: 10 }, { id: 101, name: { first: 'Brian', last: 'Eno' }, age: 43 }, { id: 103, name: { first: 'Jake', last: 'Dalton' }, age: 33 }, { id: 104, name: { first: 'Jill', last: 'Jackson' }, age: 63 } ] }; } render() { const { searchColumn, columns, rows, query } = this.state; const resolvedColumns = resolve.columnChildren({ columns }); const resolvedRows = resolve.resolve({ columns: resolvedColumns, method: resolve.nested })(rows); const searchedRows = compose( search.highlighter({ columns: resolvedColumns, matches: search.matches, query }), search.multipleColumns({ columns: resolvedColumns, query }), )(resolvedRows); return ( <div> <div className="search-container"> <span>Search</span> <search.Field column={searchColumn} query={query} columns={resolvedColumns} rows={resolvedRows} onColumnChange={searchColumn => this.setState({ searchColumn })} onChange={query => this.setState({ query })} /> </div> <Table.Provider columns={resolvedColumns} className="Table"> <Table.Header headerRows={resolve.headerRows({ columns })} /> <Table.Body rows={searchedRows} rowKey="id" /> </Table.Provider> </div> ); } } export default HighlightTable;
This problem with loading the content through the state is that it can't really be changed, and I wanted to fetch it and load it through the props. So to fix this you have to remove the rows property from the state, remove the const value in the render method that assigns its value from the state and instead assign it to the prop value.
/* import React from 'react'; import { compose } from 'redux'; import * as Table from 'reactabular-table'; import * as resolve from 'table-resolver'; import * as search from 'searchtabular'; */ class HighlightTable extends React.Component { constructor(props) { super(props); this.state = { searchColumn: 'all', query: {}, columns: [ { header: { label: 'Name' }, children: [ { property: 'name.first', header: { label: 'First Name' }, cell: { formatters: [search.highlightCell] } }, { property: 'name.last', header: { label: 'Last Name' }, cell: { formatters: [search.highlightCell] } } ] }, { property: 'age', header: { label: 'Age' }, cell: { formatters: [search.highlightCell] } } ] }; } render() { const { searchColumn, columns, query } = this.state; ///// THIS IS WHERE THE ROWS ARE LOADED THROUGH THE PROPS const rows = this.props.rows; const resolvedColumns = resolve.columnChildren({ columns }); const resolvedRows = resolve.resolve({ columns: resolvedColumns, method: resolve.nested })(rows); const searchedRows = compose( search.highlighter({ columns: resolvedColumns, matches: search.matches, query }), search.multipleColumns({ columns: resolvedColumns, query }), )(resolvedRows); return ( <div> <div className="search-container"> <span>Search <search.Field column={searchColumn} query={query} columns={resolvedColumns} rows={resolvedRows} onColumnChange={searchColumn => this.setState({ searchColumn })} onChange={query => this.setState({ query })} /> </div> <Table.Provider columns={resolvedColumns}> <Table.Header headerRows={resolve.headerRows({ columns })} /> <Table.Body rows={searchedRows} rowKey="id" /> </Table.Provider> </div> ); } } export default HighlightTable;