MongChangHsi
MongChangHsi

Reputation: 133

ReactJS unable to get search filter (text) working

I am trying to develop a very simple dashboard with some information. I'm trying to add in a search filter into my code so that I can narrow my data by names. In many other tutorials, I found that they have common used name.toLowerCase().indexOf(this.state.filterName.toLowerCase()) >= 0 but I just didn't work for me and would like to seek guidance from you guys.

You may also provide feedback on the general structure of my code!

Tables.js

class Table extends Component {
  constructor(props){
    super(props);

    this.state = {
      filterName: this.props.filterName,
      toShow: 'all',
      myArrays: [
        { 'id': 1, 'name': 'Eric', 'email': '[email protected]', 'role': 'student', 'isadmin': 'false' },
        { 'id': 2, 'name': 'Amanda', 'email': '[email protected]', 'role': 'student', 'isadmin': 'false' },
        { 'id': 3, 'name': 'Brenda', 'email': '[email protected]', 'role': 'staff', 'isadmin': 'true' },
        { 'id': 4, 'name': 'Charles', 'email': '[email protected]', 'role': 'teacher', 'isadmin': 'true' },
        { 'id': 5, 'name': 'Daimon', 'email': '[email protected]', 'role': 'assistant', 'isadmin': 'false' }
      ]
    };
    this.toShowAdmin = this.toShowAdmin.bind(this);
  }

  toShowAdmin(){
    if (this.state.toShow === 'all'){
      this.setState({ toShow: 'admin' }, () => console.log(this.state.toShow ))
    } else {
      this.setState({ toShow: 'all' }, () => console.log(this.state.toShow ))
    }
  }

  render(){
    let myArrays = []

    if (this.state.toShow === 'all'){
      myArrays = this.state.myArrays;
    } else if (this.state.toShow === 'admin'){
      myArrays = this.state.myArrays.filter(row => row.isadmin === 'true')
    }

    myArrays = this.state.myArrays.filter(row => {
      return row.name.toLowerCase().indexOf(this.state.filterName.toLowerCase()) >= 0;
    });

    return(
      <div>
        <table className="table">
          <thead className="thead-dark">
            <tr>
              <th scope="col"> name </th>
              <th scope="col"> email </th>
              <th scope="col"> role </th>
              <th scope="col"> isadmin </th>
            </tr>
          </thead>

          <tbody>
            {myArrays.map(row=>
              <tr key={row.id}>
                <td> {row.name} </td>
                <td> {row.email} </td>
                <td> {row.role} </td>
                <td> {row.isadmin} </td>
              </tr>
            )}
          </tbody>
        </table>

        <button type='button' className='btn btn-primary' onClick={this.toShowAdmin}> Admins </button>
        { this.state.filterName }
      </div>
    );
  }
}

export default Table;

Main.js

class Main extends Component {
  constructor(props){
    super(props);

    this.state = {
      filterName: ''
    };
    this.filterUpdate = this.filterUpdate.bind(this);
  }

  filterUpdate(value){
    this.setState({ filterName: value}, () => console.log(this.state.filterName))
  }

  render(){
    return(
      <div>
        <Search
          filterName={this.state.filterName}
          filterUpdate={this.filterUpdate}/>
        <Tables
          filterName={this.state.filterName}/>
      </div>
    );
  }
}

export default Main;

Upvotes: 0

Views: 67

Answers (2)

Mukesh Keshu
Mukesh Keshu

Reputation: 467

You have to use componentWillReceiveProps to update your child state with parent props once the child component has been loaded. Add something like this to child component -

componentWillReceiveProps(){
 this.setState({filterName: this.props.filterName})
}

See this Stack Over Flow Answer

Otherwise, if your logic allows you to use the prop directly in render, you may also do -

myArrays = this.state.myArrays.filter(row => {
      return row.name.toLowerCase().indexOf(this.props.filterName.toLowerCase()) >= 0;
 });

edit - use componentDidUpdate()

As rightly pointed out in comments, componentWillReceiveProps() is deprecated. Use componentDidUpdate() instead.

componentDidUpdate(){
     this.setState({filterName: this.props.filterName})
}

Upvotes: 1

Taghi Khavari
Taghi Khavari

Reputation: 6582

You should use this.props.filterName directly like this:

    myArrays = this.state.myArrays.filter(row => {
      return row.name.toLowerCase().indexOf(this.props.filterName.toLowerCase()) >= 0;
    });

Upvotes: 0

Related Questions