Derrick Omanwa
Derrick Omanwa

Reputation: 525

How do I filter a Bootstrap table based on a dropdown value in react

I have a created a table in react, based on the react-bootstrap-table-next library. I have a dropdown that I would like to use to filter the data based on the value selected on the dropdown. Below are some code snippets of what I did, in my code order.

  1. This is how I getting my data

    useEffect(() => {
    const fetchData = async () => {
        try{
            const res = await axios.get('http://X.X.X.X:8000/api/statistic/');
            setstatistics(res.data);
            setloading(true);
        } catch (e) {
            console.log(e)
        }
    }
    fetchData();
    }, []);
    
  2. These are the columns of the table

    const columns = [
    {dataField: "id", text:"id number"},
    {dataField: "query_text", text:"query text"},
    {dataField: "period", text:"period"},
    {dataField: "value", text:"value"},
    {dataField: "total", text:"total"},
    {dataField: "ratio", text:"ratio"},
    

    ];

  3. This is one of the filters I am using, if filters the table based on the value of the period.

            <p>PERIOD</p>
            <select>
                {Array.from(new Set(statistics.map(obj => obj.period))).map(period => {
                    return <option value={period}>{period}</option>
                })}
            </select>
    
  4. This is how I display my table

                 <BootstrapTable
                keyField="id"
                striped
                data={statistics}
                columns={columns}
                filter={filterFactory()}
                pagination={paginationFactory()}
                />
    

    How could I achieve filtering the data, {statistics} based on the period dropdown selection in '2' above? Thanks

Upvotes: 1

Views: 2563

Answers (1)

A. Ecrubit
A. Ecrubit

Reputation: 609

You can use a selectedValue variable in your state. Each time you update your dropdown list : update the selected value.

Then when you render the component pass to the list a filterData variable which will be your data filtered according to the selectedValue (just use js filter() method).

  • with Class components : you need to add your logic for thee filter variable in the render() method.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      contacts: [
        {
          first_name: "Melloney",
          country: "Russia"
        },
        {
          first_name: "Fayre",
          country: "Russia"
        },
        {
          first_name: "Bernhard",
          country: "France"
        },
        {
          first_name: "Lauren",
          country: "China"
        },
        {
          first_name: "Terza",
          country: "China"
        }
      ],
      countries: ["All", "China", "Russia", "France"],
      countrySelected: "All"
    };
  }

  handleChange = e => {
    this.setState({ countrySelected: e.target.value });
  };

  componentDidMount() {
    this.setState({ filteredContacts: this.state.contacts });
  }

  render() {
    let filteredContacts = this.state.contacts;

    if (this.state.countrySelected !== "All") {
      filteredContacts = this.state.contacts.filter(
        contact => contact.country == this.state.countrySelected
      );
    }

    return (
      <div>
        <div>
          Countries : 
          &nbsp;<select onChange={e => this.handleChange(e)}>
            {this.state.countries.map(country => (
              <option key={country} value={country}>
                {country}
              </option>
            ))}
          </select>
        </div>
        <table>
          <tr>
            <th>Name</th>
            <th>Country</th>
          </tr>
          {filteredContacts.map((contact, id) => (
            <tr key={id}>
              <td>{contact.first_name}</td>
              <td>{contact.country}</td>
            </tr>
          ))}
        </table>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
table {
  margin-top: 1em;
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td, th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>

  • with Functional component : the logic for the filterData will be put directly in your function and it will be rerendered accordingly.

function App() {
    const [contacts, setContacts] = React.useState([{
      "first_name": "Melloney",
      "country": "Russia"
    }, {
      "first_name": "Fayre",
      "country": "Russia"
    }, {
      "first_name": "Bernhard",
      "country": "France"
    }, {
      "first_name": "Lauren",
      "country": "China"
    }, {
      "first_name": "Terza",
      "country": "China"
    }]);
    const [countries, setCountries] = React.useState(["All", "China", "Russia", "France"]);
    const [countrySelected, setSelected] = React.useState("All");

    const handleChange = e => {
      setSelected(e.target.value)
    }

    let filteredContacts = contacts;
    if (countrySelected !== "All") {
      filteredContacts = contacts.filter(contact => contact.country == countrySelected);
    }

    return (
        <div>
          <div className="header">
            Countries :
            <select
                onChange={e => handleChange(e)}>
              {countries.map(country =>
                  <option key={country} value={country}>{country}</option>
              )}
            </select>
          </div>
          <table>
            <tr>
              <th>Name</th>
              <th>Country</th>
            </tr>
            {filteredContacts.map((contact, id) =>
                  <tr key={id}>
                    <td>{contact.first_name}</td>
                    <td>{contact.country}</td>
                  </tr>
            )}
          </table>
        </div>
    )
  }
  ReactDOM.render(<App/>, document.getElementById('root'))
.header * {
  justify-content: center;
  font-size: 1em;
  margin: 1em;
}

table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td, th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 4px;
}

tr:nth-child(even) {
  background-color: #dddddd;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions