Aaron
Aaron

Reputation: 110

Using React-table to filter rows based on meta-data

I know how to filter rows based on content that is rendered in the table, but how could I filter (using useFilters) a table based on information which isn't shown in the table, but is available in the data-set?

I figure I could let react-table show the tags/meta-data in the table and just hide it with styling, but that seems not too good.

Example data:

{title:"Lesson One", author:"Joe", category:"math"}

Where title and author are shown in the table, but category is only used for filtering.

Upvotes: 2

Views: 2574

Answers (1)

jpotts17
jpotts17

Reputation: 446

My solution for this isn't the most elegant, but perhaps you can adapt it to fit your needs. I used the react-table examples to do most of the boilerplate, so the fields do not match with the example fields you gave but hopefully you can adapt it.

https://codesandbox.io/s/vigorous-ardinghelli-z7fc1?file=/src/App.js

In summary:

Any fields that you do not want shown you can hide on table creation by passing the hiddenColumns property an array of string IDs.

const {
  ...
} = useTable(
  {
    columns,
    data,
    initialState: {
      hiddenColumns: ["firstName"] // In your case, "category"
    }
  },
  useFilters
);

I obtained an array of hidden columns from the table instance (line 86)

// Obtain an array of the hidden columns so we can render the filter for them
const hiddenColumns = React.useMemo(() => {
  return allColumns.filter(
    (column) => column.id === state.hiddenColumns.find(
        (columnId) => columnId === column.id))
}, [allColumns, state.hiddenColumns])

Note however that the allColumns property returns a flat array of columns, meaning that if you have nested columns then it does not track that information, instead you will need to use the columns property and modify the filtering to match your column nesting (if tracking the nesting is necessary for you). Ref

Once I obtain the hidden columns I can render Filter for each of them, depending on if canFilter is true or false, followed by the visible columns. (line 111)

<thead>
  {hiddenColumns.map(hiddenColumn => {
     return hiddenColumn.canFilter ? 
       <tr key={hiddenColumn.id} role="row">
         <th colSpan={visibleColumns.length} style={{ textAlign: 'left'}}>
           {hiddenColumn.render('Filter')}
         </th>
       </tr> : null
     })}
     {headerGroups.map(headerGroup => (
       <tr {...headerGroup.getHeaderGroupProps()}>
         {headerGroup.headers.map(column => (
           <th {...column.getHeaderProps()}>
             {column.render('Header')}
             <div>{column.canFilter ? column.render('Filter') : null}</div>
           </th>
         ))}
      </tr>
   ))}
</thead>

You can obviously change the positioning of where the filter for hidden columns is rendered to suite your needs.

Also I will mention that the hook useGlobalFilter searches on hidden columns, so if you were looking for a global filter solution then it should work without any workarounds.

Upvotes: 2

Related Questions