Neil Kelsey
Neil Kelsey

Reputation: 841

React-table dynamic drop down reusable custom filter

I've got a react-table where I want to add some custom filtering

What I'm trying to achieve is a drop-down selector which is dynamically populated with all the available choices

I'm almost there and have a working solution but what I'd really like to do is make my customFilter reusable for each of the three fields, first name, last name and age - currently it works but is hardcoded for each value

So this line

.map(item => item.lastName)

Needs to be something like

.map(item => item.{accessor})

That doesn't work but idea is that I could get the accessor value for each of the fields and then this would be truly dynamic and reusable

const customFilter = ({ filter, onChange }) => {
    return (
      <select
        onChange={event => onChange(event.target.value)}
        style={{ width: "100%" }}
        value={filter ? filter.value : "all"}
      > 
        <option value="all">Show All</option>
        {testData
          .map(item => item.lastName)
          
          .filter((item, i, s) => s.lastIndexOf(item) == i)
          .map(function (value) {
            log.debug('renderItem: ', value);
            return (
              <option key={value} value={value}>
                {value}
              </option>
            );
          })}
      </select>
    );
  };

  const testData = [
    { firstName: 'Aang', lastName: 'Smith', age: '19' },
    { firstName: 'Appa', lastName: 'Baker', age: '3' },
    { firstName: 'Asami', lastName: 'Smith', age: '19' },
    { firstName: 'Azula', lastName: 'Baker', age: '19' },
    { firstName: 'Bolin', lastName: 'Smith', age: '20' },
    { firstName: 'Jinora', lastName: 'Baker', age: '19' },
    { firstName: 'Katara', lastName: 'Smith', age: '8' },
    { firstName: 'Korra', lastName: 'Baker', age: '19' },
    { firstName: 'Lin Beifong', lastName: 'Smith', age: '19' },
    { firstName: 'Momo', lastName: 'Baker', age: '19' },
    { firstName: 'Mai', lastName: 'Smith', age: '8' },
    { firstName: 'Mako', lastName: 'Baker', age: '29' },
    { firstName: 'Naga', lastName: 'Smith', age: '19' },
    { firstName: 'Pabu', lastName: 'Baker', age: '19' },
    { firstName: 'Sokka', lastName: 'Smith', age: '39' },
    { firstName: 'Suki', lastName: 'Baker', age: '8' },
    { firstName: 'Tenzin', lastName: 'Smith', age: '19' },
    { firstName: 'Toph Beifong', lastName: 'Baker', age: '19' },
    { firstName: 'Ty Lee', lastName: 'Smith', age: '49' },
    { firstName: 'Uncle Iroh', lastName: 'Baker', age: '59' },
    { firstName: 'Varrick', lastName: 'Smith', age: '19' },
    { firstName: 'Zhu Li', lastName: 'Baker', age: '8' },
    { firstName: 'Zuko', lastName: 'Smith', age: '19' }
  ];


  const columns = [
    {
      Header: "First Name",
      accessor: "firstName", 
      filterMethod: (filter, row) =>
        row[filter.id].startsWith(filter.value) &&
        row[filter.id].endsWith(filter.value)
    }, {
      Header: "Last Name",
      id: "lastName",
      accessor: d => d.lastName,
      filterMethod: (filter, row) => {
        return row[filter.id] === filter.value;
      },
      Filter: ({ filter, onChange }) =>
        customFilter({ filter, onChange })
    }, {
      Header: "Age",
      accessor: "age",
      filterMethod: (filter, row) => {
        return row[filter.id] === filter.value;
      },
      Filter: ({ filter, onChange }) =>
        customFilter({ filter, onChange })
    }
  ]


  return (
    <div>
    <ReactTable
      data={testData}
      filterable
      defaultFilterMethod={(filter, row) =>
        String(row[filter.id]) === filter.value}
      columns={columns}
      defaultPageSize={10}
      className="-striped -highlight"
    />
      <br />
    </div>
  );

Upvotes: 3

Views: 8756

Answers (1)

Neil Kelsey
Neil Kelsey

Reputation: 841

Found a solution

So for each of the columns filters I gave it a fieldName variable - I can then just call that to change the value and make this reusable

So this line

.map(item => item.lastName)

Becomes this

.map(item => item[fieldName])

Works great :-)

const customFilter = ({ fieldName, filter, onChange }) => {

    return (
      <select
        onChange={event => onChange(event.target.value)}
        style={{ width: "100%" }}
        value={filter ? filter.value : "all"}
      > 
        <option value="all">Show All</option>
        {testData
          .map(item => item[fieldName])

          .filter((item, i, s) => s.lastIndexOf(item) == i)
          .map(function (value) {
            log.debug('renderItem: ', value);
            return (
              <option key={value} value={value}>
                {value}
              </option>
            );
          })}
      </select>
    );
  };

  const testData = [
    { firstName: 'Aang', lastName: 'Smith', age: '19' },
    { firstName: 'Appa', lastName: 'Baker', age: '3' },
    { firstName: 'Asami', lastName: 'Smith', age: '19' },
    { firstName: 'Azula', lastName: 'Baker', age: '19' },
    { firstName: 'Bolin', lastName: 'Smith', age: '20' },
    { firstName: 'Jinora', lastName: 'Baker', age: '19' },
    { firstName: 'Katara', lastName: 'Smith', age: '8' },
    { firstName: 'Korra', lastName: 'Baker', age: '19' },
    { firstName: 'Lin Beifong', lastName: 'Smith', age: '19' },
    { firstName: 'Momo', lastName: 'Baker', age: '19' },
    { firstName: 'Mai', lastName: 'Smith', age: '8' },
    { firstName: 'Mako', lastName: 'Baker', age: '29' },
    { firstName: 'Naga', lastName: 'Smith', age: '19' },
    { firstName: 'Pabu', lastName: 'Baker', age: '19' },
    { firstName: 'Sokka', lastName: 'Smith', age: '39' },
    { firstName: 'Suki', lastName: 'Baker', age: '8' },
    { firstName: 'Tenzin', lastName: 'Smith', age: '19' },
    { firstName: 'Toph Beifong', lastName: 'Baker', age: '19' },
    { firstName: 'Ty Lee', lastName: 'Smith', age: '49' },
    { firstName: 'Uncle Iroh', lastName: 'Baker', age: '59' },
    { firstName: 'Varrick', lastName: 'Smith', age: '19' },
    { firstName: 'Zhu Li', lastName: 'Baker', age: '8' },
    { firstName: 'Zuko', lastName: 'Smith', age: '19' }
  ];


  const columns = [
    {
      Header: "First Name",
      accessor: "firstName", 
      filterMethod: (filter, row) =>
        row[filter.id].startsWith(filter.value) &&
        row[filter.id].endsWith(filter.value)
    }, {
      Header: "Last Name",
      id: "lastName",
      accessor: d => d.lastName,
      filterMethod: (filter, row) => {
        return row[filter.id] === filter.value;
      },
      Filter: ({ filter, onChange }) =>
        customFilter({ fieldName:'lastName', filter, onChange })
    }, {
      Header: "Age",
      accessor: "age",
      filterMethod: (filter, row) => {
        return row[filter.id] === filter.value;
      },
      Filter: ({ filter, onChange }) =>
        customFilter({ fieldName:'age', filter, onChange })
    }
  ]


  return (
    <div>
    <ReactTable
      data={testData}
      filterable
      defaultFilterMethod={(filter, row) =>
        String(row[filter.id]) === filter.value}
      columns={columns}
      defaultPageSize={10}
      className="-striped -highlight"
    />
      <br />
    </div>
  );

Upvotes: 7

Related Questions