customise ant design's table search function so numeric search will return less than or greater than, not only equals

Viewed 3969

As far as I can see ant design's table currently doesn't ship with a specific numeric search, where I can return results within a specific range, example >10 or <=50.

Given the below example: codesandbox

import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Table, Input, Button, Icon } from 'antd';
import Highlighter from 'react-highlight-words';

const data = [
  {
    key: '1',
    name: 'John Brown',
    age: 32,
    address: 'New York No. 1 Lake Park',
  },
  {
    key: '2',
    name: 'Joe Black',
    age: 42,
    address: 'London No. 1 Lake Park',
  },
  {
    key: '3',
    name: 'Jim Green',
    age: 32,
    address: 'Sidney No. 1 Lake Park',
  },
  {
    key: '4',
    name: 'Jim Red',
    age: 32,
    address: 'London No. 2 Lake Park',
  },
];

class App extends React.Component {
  state = {
    searchText: '',
  };

  getColumnSearchProps = dataIndex => ({
    filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
      <div style={{ padding: 8 }}>
        <Input
          ref={node => {
            this.searchInput = node;
          }}
          placeholder={`Search ${dataIndex}`}
          value={selectedKeys[0]}
          onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
          onPressEnter={() => this.handleSearch(selectedKeys, confirm)}
          style={{ width: 188, marginBottom: 8, display: 'block' }}
        />
        <Button
          type="primary"
          onClick={() => this.handleSearch(selectedKeys, confirm)}
          icon="search"
          size="small"
          style={{ width: 90, marginRight: 8 }}
        >
          Search
        </Button>
        <Button onClick={() => this.handleReset(clearFilters)} size="small" style={{ width: 90 }}>
          Reset
        </Button>
      </div>
    ),
    filterIcon: filtered => (
      <Icon type="search" style={{ color: filtered ? '#1890ff' : undefined }} />
    ),
    onFilter: (value, record) =>
      record[dataIndex]
        .toString()
        .toLowerCase()
        .includes(value.toLowerCase()),
    onFilterDropdownVisibleChange: visible => {
      if (visible) {
        setTimeout(() => this.searchInput.select());
      }
    },
    render: text => (
      <Highlighter
        highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
        searchWords={[this.state.searchText]}
        autoEscape
        textToHighlight={text.toString()}
      />
    ),
  });

  handleSearch = (selectedKeys, confirm) => {
    confirm();
    console.log(selectedKeys);
    this.setState({ searchText: selectedKeys[0] });
  };

  handleReset = clearFilters => {
    clearFilters();
    this.setState({ searchText: '' });
  };

  render() {
    const columns = [
      {
        title: 'Name',
        dataIndex: 'name',
        key: 'name',
        width: '30%',
        ...this.getColumnSearchProps('name'),
      },
      {
        title: 'Age',
        dataIndex: 'age',
        key: 'age',
        width: '20%',
        ...this.getColumnSearchProps('age'),
      },
      {
        title: 'Address',
        dataIndex: 'address',
        key: 'address',
        ...this.getColumnSearchProps('address'),
      },
    ];
    return <Table columns={columns} dataSource={data} />;
  }
}

ReactDOM.render(<App />, document.getElementById('container'));

Let's look at the age column, if we specify an exact age, exact results will be returned. On the input element when the value is keyed in, on either enter press or onClick, handleSearch is triggered, handleSearch then sets the react state, then the component is re-rendered, all basic react functionality.

I am unsure where is the logic that sets what supposed to be returned so unsure where and how should I implement custom logic to check for a specific range of numbers rather than an exact number. Any ideas?

Alternatively, I checked if a numeric search/filter already exists for ant-design, but I couldn't find anything.

For further reference, see ant-designs table documentation

2 Answers

You can render whatever filter you like, for example using Slider and InputNumber combination:

enter image description here

filterDropdown: ({ setSelectedKeys, selectedKeys, confirm }) => (
  <div style={{ padding: 8 }}>
    <Row
      type="flex"
      gutter={10}
      style={{ marginBottom: 8, alignItems: "center" }}
    >
      <Col>Range:</Col>
      <Col>
        <InputNumber
          value={this.state.left}
          onChange={e => {
            this.setState({ left: e });
            setSelectedKeys(data.filter(d => e <= d.age).map(d => d.key));
          }}
        />
      </Col>
      <Col>
        <InputNumber
          value={this.state.right}
          onChange={e => {
            this.setState({ right: e });
            setSelectedKeys(data.filter(d => d.age <= e).map(d => d.key));
          }}
        />
      </Col>
    </Row>
    <Row>
      <Slider
        range
        value={[this.state.left, this.state.right]}
        onChange={e => this.setState({ left: e[0], right: e[1] })}
      />
    </Row>
    <Row>
      <Button
        type="primary"
        block
        size="small"
        onClick={() => {
          this.handleSearchAge(selectedKeys, confirm);
          setSelectedKeys(
            data
              .filter(
                d => this.state.left <= d.age && d.age <= this.state.right
              )
              .map(d => d.key)
          );
        }}
      >
        Confirm
      </Button>
    </Row>
  </div>
);

Edit Q-56781764-SliderInTableFilter

i wonder if you still have the example, the link is broke

Related