Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement filtering logic in React table?

Im using React Table to display data I receive from an API call. Currently I save the state locally and the table displays the data. I have added filtering of column values for two columns. My filtering logic is as follows:

    <ReactTable
  data={tableData}
  noDataText="Loading.."
  filterable
  defaultFilterMethod={(filter, row) =>
    String(row[filter.id]) === filter.value}
    };
  }}
  columns={[
    {
      columns: [
        {
          Header: 'Name',
          accessor: 'Name',
          id: 'Name',
          Cell: ({ value }) => (value === 'group1' ? 
          'group1' : 'group2'),
          filterMethod: (filter, row) => {
            if (filter.value === 'all') {
              return true;
            }
            if (filter.value === 'group1') {
              return row[filter.id] === 'group1';
            }
            if (filter.value === 'group2') {
              return row[filter.id] === 'group2';
            }
          },
          Filter: ({ filter, onChange }) =>
            <select
              onChange={event => onChange(event.target.value)}
              style={{ width: '100%' }}
              value={filter ? filter.value : 'all'}
            >
              <option value="all">All</option>
              <option value="group1">Group1</option>
              <option value="group2">Group2</option>
            </select>,
        },
   }

As of now, the filtering rule is hard coded between two values. How to implement the filter logic so that the filtering is dynamic?(If there are 3 or 7 different values in a particular column, the dropdown should display all 7 values and filter should work based on any of the value selected). Since Im using React Table(https://react-table.js.org).

like image 294
SeaWarrior404 Avatar asked Jan 30 '23 14:01

SeaWarrior404


2 Answers

I assume you wanted to make options out of list of options. If so, here is a way you can do it:

const exampleList = ['option1','option2','option3','option4',...,'option n']

In your column:

filterMethod:  (filter, row) => customOptionsFilterMethod(filter, row),
Filter: () => ({filter, onChange}) => customOptionsFilter({filter, onChange})

Inside render() implement customOptionsFilter and customOptionsFilterMethod as:

const customOptionsFilter = ({filter, onChange}) => {
      return(
        <select
          onChange={e => onChange(e.target.value)}
          style={{  width: '100%'  }}
          value={filter ? filter.value : 'all'}
          >
          <option value='all'>Show All</option>
          {
            exampleList.map( k => {
              return <option key={k.toString()} value={k}>{k}</option>
            })
          }
        </select>
      )
    }



const customOptionsFilterMethod = (filter, row) => {

      if(filter.value === '') { return true }

      if(exampleList.includes(filter.value)){
        return row[filter.id] === filter.value
      } else { return true }

    }
like image 149
bh4r4th Avatar answered Feb 01 '23 03:02

bh4r4th


Haven't used the library, but it kind of sounds like something like this would work

if (filter.value === 'all') {
  return true;
} else {
  // what ever the value is, we will only
  // show rows that have a column value
  // that matches it
  // If value is 'group1' just show the ones where the column
  // value is 'group1', etc etc.
  return row[filter.id] == filter.value;
}

Note that this will show nothing untill you get an exact match. So even if you have column values like "group1" the search term "grou" will not match it. If that's not the behaviour you want then you'd want to switch out

return row[filter.id] == filter.value;

to something like

return row[filter.id].indexOf(filter.value) >= 0;

As an alternative, if you need it to be more restricted than that, you could build your options from an array

const options = [ { value: "all" , label: "All" }, { value: "group1" , label: "Group1" }];

And use it like

       <select
          onChange={event => onChange(event.target.value)}
          style={{ width: '100%' }}
          value={filter ? filter.value : 'all'}
        >
          { options.map(({value,label}) => <option value={value}>{label}</option>)}
        </select>,

And in your filter logic you could check if the filter.value value is in the 'options` array.

// check if there is some (any) value that matches the criteria
// of opt.value == filter.value
return  options.some(opt => opt.value == filter.value);
like image 39
jonahe Avatar answered Feb 01 '23 03:02

jonahe