I am trying to implement a global search filter that searches for the key across the entire table. I am attaching a change handler and on every input I trigger a callback that searches that key across that data and the value is being set.It is getting filtered as I type-in the characters but I want the search to work when I enter multiple serach values like string1,string2 in the search input
Code Sandbox: https://codesandbox.io/s/jolly-bhabha-iqcx1
import React from "react";
import ReactDOM from "react-dom";
import { Input } from "semantic-ui-react";
import ReactTable from "react-table";
import "react-table/react-table.css";
import "./styles.css";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [
{ firstName: "aaaaa", status: "Pending", visits: 155 },
{ firstName: "aabFaa", status: "Pending", visits: 155 },
{ firstName: "adaAAaaa", status: "Approved", visits: 1785 },
{ firstName: "aAaaaa", status: "Approved", visits: 175 },
{ firstName: "adaSaaa", status: "Cancelled", visits: 165 },
{ firstName: "aasaaa", status: "Cancelled", visits: 157 },
{ firstName: "aweaaaaaewea", status: "Approved", visits: 153 },
{ firstName: "aaaaaa", status: "Submitted", visits: 155 }
],
columns: [],
searchInput: ""
};
}
componentDidMount() {
let columns = [
{
Header: "First Name",
accessor: "firstName",
sortable: false,
show: true,
displayValue: " First Name"
},
{
Header: "Status",
accessor: "status",
sortable: false,
show: true,
displayValue: "Status "
},
{
Header: "Visits",
accessor: "visits",
sortable: false,
show: true,
displayValue: " Visits "
}
];
this.setState({ columns });
}
handleChange = event => {
this.setState({ searchInput: event.target.value }, () => {
this.globalSearch();
});
};
globalSearch = () => {
let { data, searchInput } = this.state;
if (searchInput) {
let filteredData = data.filter(value => {
return (
value.firstName.toLowerCase().includes(searchInput.toLowerCase()) ||
value.status.toLowerCase().includes(searchInput.toLowerCase()) ||
value.visits
.toString()
.toLowerCase()
.includes(searchInput.toLowerCase())
);
});
this.setState({ data: filteredData });
}
};
render() {
let { data, columns, searchInput } = this.state;
return (
<div>
<br />
<Input
size="large"
name="searchInput"
value={searchInput || ""}
onChange={this.handleChange}
label="Search"
/>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
className="-striped -highlight"
/>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
This is not a problem with react-table. In the current implementation,
for the very first time, you're filtering from original data.
Second time when you try to filter, you're trying to filter results from previously filtered data(the current data in state object is filtered results of previous attempt).
I suggest to try(this is forked from yours): https://codesandbox.io/s/eloquent-clarke-w1ehv
Maintain your original data as immutable source, and filter from it every time your search input is changed rather than filtering from current data object in the state. Take a look at the fork I've attached.
If your data is coming from ajax call, you should probably maintain two state variables:
this.state = {
data: [],
filteredData: [],
columns: [],
searchInput: ""
};
componentDidMount() {
yourapicall.then(data => {
this.setState({
data // whatever data you get.
});
});
}
// And in your global search
globalSearch = () => {
let { searchInput, data } = this.state;
let filteredData = data.filter(value => {
return (
value.firstName.toLowerCase().includes(searchInput.toLowerCase()) ||
value.status.toLowerCase().includes(searchInput.toLowerCase()) ||
value.visits
.toString()
.toLowerCase()
.includes(searchInput.toLowerCase())
);
});
this.setState({ filteredData });
};
And conditionally render your react-table
<ReactTable
data={filteredData && filteredData.length ? filteredData : data}
columns={columns}
defaultPageSize={10}
className="-striped -highlight"
/>
Hope this is helpful!