React-table: Filter all columns from a single box outside of the table

Created on 3 May 2018  路  13Comments  路  Source: tannerlinsley/react-table

Is there an API to invoke the filter function of each (or some) of the columns from outside the table?

We want to have a search box outside of the table and to be able to enter values. Like for example:

To search the first and last name in the searchbox:
image

(of course we don't have such simple columns that can be merged)

Most helpful comment

There is no API for this in ReactTable.

Only two choices (well three):

  • do what I think you were hinting at and create a "hidden" (width zero) column and filter on that
  • filter the data externally (if it is so complex - then your filter logic will be complex and can't possibly be done by a generic table tool like ReactTable) and the just update your ReactTable data state with the filtered data

The third option is to use a different package if the other options are not suitable.

The following is a very basic example of the first option:

https://codesandbox.io/s/r74mokr5x4

All 13 comments

There is no API for this in ReactTable.

Only two choices (well three):

  • do what I think you were hinting at and create a "hidden" (width zero) column and filter on that
  • filter the data externally (if it is so complex - then your filter logic will be complex and can't possibly be done by a generic table tool like ReactTable) and the just update your ReactTable data state with the filtered data

The third option is to use a different package if the other options are not suitable.

The following is a very basic example of the first option:

https://codesandbox.io/s/r74mokr5x4

Great example, it works perfectly with what I need. And I think you can create truly hidden filter column by adding below to All column.

getProps: () => ({ style: { padding: "0px" } }),
getHeaderProps: () => ({ style: { padding: 0 } }),

Closing due to issue age. If this issue was a question, please ask it again on https://spectrum.chat/react-table. If you think this issue needs to be reopened or if it should be turned into a pull-request, please check the latest version of React-Table for the issue or feature once more and reopen or create a PR if appropriate. Thanks!

There is no API for this in ReactTable.

Only two choices (well three):

  • do what I think you were hinting at and create a "hidden" (width zero) column and filter on that
  • filter the data externally (if it is so complex - then your filter logic will be complex and can't possibly be done by a generic table tool like ReactTable) and the just update your ReactTable data state with the filtered data

The third option is to use a different package if the other options are not suitable.

The following is a very basic example of the first option:

https://codesandbox.io/s/r74mokr5x4

Is it possible that even the column is invisible, the column can still be filtered?

Yes, that's possible in v6 :)

My solution:
I created decorator(HOC) for my table and implemented search logic in decorator.

/* eslint-disable react/prop-types */
import React, { Component } from 'react'

const tableDecorator = (Table) => class WrappedTable extends Component {
  constructor(props) {
    super(props)
    this.state = {
      term: '',
    }

    this.methods = {
      filterCaseInsensitive: ::this.filterCaseInsensitive,
      filterFunction: ::this.filterFunction,
      onSearchChange: ::this.onSearchChange,
    }

    const { columns } = props
    this.columns = columns.map((c) => { // getting column names
      const {
        id,
        accessor,
      } = c
      return typeof accessor === 'string' ? accessor : id
    })
  }

  onSearchChange(term) {
    this.setState({ term })
  }

  /* used for filtering data in withSearchField mode */
 /* Common function for filtering each column in each row. */
  filterFunction(row) {
    let res = false
    const { term } = this.state
    for(let i = 0; i < this.columns.length; i += 1) {
      const val = row[this.columns[i]]
      if(!Array.isArray(val)) {
        if(String(val).toLowerCase().includes(term.toLowerCase())) {
          res = true
          break
        }
      } else {
        for(let j = 0; i < val.length; j += 1) {
          if(String(val[j]).toLowerCase().includes(term.toLowerCase())) {
            res = true
            break
          }
        }
      }
    }
    return res
  }

  filterCaseInsensitive(filter, row) {
    const id = filter.pivotId || filter.id
    return (
      row[id] !== undefined
        ? String(row[id].toString().toLowerCase()).startsWith(filter.value.toLowerCase())
        : true
    )
  }

  render() {
    const {
      withSearchField,
    } = this.props

    let {
      data,
    } = this.props

    if(withSearchField) { // if withSearchField prop is true then we filter data
      data = data.filter(this.methods.filterFunction)
    }

    return (
      <Table
        {...this.props}
        {...this.methods}
        data={data}
      />
    )
  }
}

export default tableDecorator
**Next i implemented stupid component with table mark up.**
import React, { Fragment } from 'react'
import ReactTable from 'react-table'
import { defaultProps, propTypes } from './tablePropTypes'
import tableDecorator from './tableDecorator'
import './TableBlank.scss'
import TextBox from '../TextBox'

const TableBlank = ({
  data,
  columns,
  resizable,
  loading,
  defaultPageSize,
  filterCaseInsensitive,
  withSearchField,
  onSearchChange,
  term,
}) => (
  <Fragment>
    {
      withSearchField &&
      <div className="table-up-div">
        <div className="table-filter-field">
          <TextBox
            value={term}
            placeholder="Search"
            onChange={onSearchChange}
          />
        </div>
      </div>
    }
    <ReactTable
      data={data}
      columns={columns}
      resizable={resizable}
      loading={loading}
      defaultPageSize={defaultPageSize}
      className="-highlight"
      defaultFilterMethod={filterCaseInsensitive}
    />
  </Fragment>
)

TableBlank.defaultProps = defaultProps
TableBlank.propTypes = propTypes

export default tableDecorator(TableBlank)



md5-4fd40fd056a989b2cf973fbd57c9a2d4



import Table from '../Table' // import decorated table
 ...
in render
            <Table
              columns={this.state.columns}
              loading={this.state.loading}
              data={this.state.usersList}
              withSearchField // pass this param=true if you want show table with search field.
            />

My solution:
I created decorator(HOC) for my table and implemented search logic in decorator.

/* eslint-disable react/prop-types */
import React, { Component } from 'react'

const tableDecorator = (Table) => class WrappedTable extends Component {
  constructor(props) {
    super(props)
    this.state = {
      term: '',
    }

    this.methods = {
      filterCaseInsensitive: ::this.filterCaseInsensitive,
      filterFunction: ::this.filterFunction,
      onSearchChange: ::this.onSearchChange,
    }

    const { columns } = props
    this.columns = columns.map((c) => { // getting column names
      const {
        id,
        accessor,
      } = c
      return typeof accessor === 'string' ? accessor : id
    })
  }

  onSearchChange(term) {
    this.setState({ term })
  }

  /* used for filtering data in withSearchField mode */
 /* Common function for filtering each column in each row. */
  filterFunction(row) {
    let res = false
    const { term } = this.state
    for(let i = 0; i < this.columns.length; i += 1) {
      const val = row[this.columns[i]]
      if(!Array.isArray(val)) {
        if(String(val).toLowerCase().includes(term.toLowerCase())) {
          res = true
          break
        }
      } else {
        for(let j = 0; i < val.length; j += 1) {
          if(String(val[j]).toLowerCase().includes(term.toLowerCase())) {
            res = true
            break
          }
        }
      }
    }
    return res
  }

  filterCaseInsensitive(filter, row) {
    const id = filter.pivotId || filter.id
    return (
      row[id] !== undefined
        ? String(row[id].toString().toLowerCase()).startsWith(filter.value.toLowerCase())
        : true
    )
  }

  render() {
    const {
      withSearchField,
    } = this.props

    let {
      data,
    } = this.props

    if(withSearchField) { // if withSearchField prop is true then we filter data
      data = data.filter(this.methods.filterFunction)
    }

    return (
      <Table
        {...this.props}
        {...this.methods}
        data={data}
      />
    )
  }
}

export default tableDecorator
**Next i implemented stupid component with table mark up.**
import React, { Fragment } from 'react'
import ReactTable from 'react-table'
import { defaultProps, propTypes } from './tablePropTypes'
import tableDecorator from './tableDecorator'
import './TableBlank.scss'
import TextBox from '../TextBox'

const TableBlank = ({
  data,
  columns,
  resizable,
  loading,
  defaultPageSize,
  filterCaseInsensitive,
  withSearchField,
  onSearchChange,
  term,
}) => (
  <Fragment>
    {
      withSearchField &&
      <div className="table-up-div">
        <div className="table-filter-field">
          <TextBox
            value={term}
            placeholder="Search"
            onChange={onSearchChange}
          />
        </div>
      </div>
    }
    <ReactTable
      data={data}
      columns={columns}
      resizable={resizable}
      loading={loading}
      defaultPageSize={defaultPageSize}
      className="-highlight"
      defaultFilterMethod={filterCaseInsensitive}
    />
  </Fragment>
)

TableBlank.defaultProps = defaultProps
TableBlank.propTypes = propTypes

export default tableDecorator(TableBlank)

Feel free to use your own instead of my component.
How to use:

import Table from '../Table' // import decorated table
 ...
in render
            <Table
              columns={this.state.columns}
              loading={this.state.loading}
              data={this.state.usersList}
              withSearchField // pass this param=true if you want show table with search field.
            />

Why dont you create a library out of that? Have a generic impl, so that everyone wont have to going through defining one on their own?

How would you do this using useTable in version 7?

I've gone with just working my custom filters into the useMemo call which provides the data to the table. If there's a "more correct" way I'd like to hear about it.

Please see #1527

In my particular case I'm not looking to filter on all columns in a standardized way, rather just a subset of columns and in some cases I'd almost certainly need custom logic.

I see. In that case, then you can easily just keep using useMemo on your table data before it enters the table.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

missmellyg85 picture missmellyg85  路  3Comments

alexanderwhatley picture alexanderwhatley  路  3Comments

ocalde picture ocalde  路  3Comments

krishna-shenll picture krishna-shenll  路  3Comments

dwjft picture dwjft  路  3Comments