user7597670
user7597670

Reputation:

Arrays - Javascript - filter array of objects using input search

I am trying to filter a list using react, but surprisingly, for such a common task, cannot find anything online to help me achieve this.

I have an array of users which I then want to filter through (starting off with name - I can work out filtering by age then). The array is in my redux store and looks like the below.

let users = [
  {
    name: 'Raul',
    age: 29
  },
  {
    name: 'Mario',
    age: 22
  }
];

My entire component looks like the below.

class Test extends Component {

    constructor(props) {
        super(props);

        this.state = {
            users: this.props.users

        };

        this.filterList = this.filterList.bind(this);

    }

    componentWillReceiveProps(nextProps) {

        this.setState({
            users: nextProps.users
        });

    }

    filterList(event) {

        let users = this.state.users;
        users = users.filter(function(user){
        //unsure what to do here
        });
        this.setState({users: users});
    }

  render(){

    const userList = this.state.users.map((user) => {
      return <li>{user.name} {user.age}</li>;
    });

    return(
      <input type="text" placeholder="Search" onChange={this.filterList}/>
      <ul>
        { userList }
      </ul>
    );

  }
}

Upvotes: 2

Views: 15664

Answers (5)

Rafael In&#225;cio
Rafael In&#225;cio

Reputation: 191

It always worked well for me that way.

const [data, setData] = useState([{name: 'Kondo'}, {name: 'Gintoki'}])

const handleFilterFilesTable = () => {
    return data
      .filter((element) => {
        if (searchText !== "") {
          return element?.name?.toLowerCase()?.includes(searchText?.toLowerCase())
        }

        return element
      })
  }

// ...
return (
 //...
 <Table data={handleFilterFilesTable()} />
)

That way I can apply multiple filters working together simply by extending the filter method like this

// ...
return data.filter().filter().filter()//...
// ...

Upvotes: 0

Vinesh sarathy
Vinesh sarathy

Reputation: 21

let datas =[
  {   
      "id":1,
      "title":"Ucat",
      "handle":"mi"
  },
  {
      "id":2,
      "title":"Acat",
      "handle":"csk"
  },
  {
      "id":3,
      "title":"Vcat",
      "handle":"kkr"
  },
  {
      "id":4,
      "title":"Atar",
      "handle":"pkbs"
  }];
const [search, setSearch] =useState(datas);
const handleInputChange = (e) => {
var dm = e.target.value;
var str =dm.toString();
var debug = datas.filter(x=> x["title"].toLowerCase().includes(str));
setSearch(debug);};


<input type="text"  onChange={handleInputChange}/>
{search.map((item)=>(
    <div key={item.id}>
        <ul>
            <li>
            {item.handle} 
            <br/>
            {item.title}
            </li>
        </ul>
    </div>
))};
  
  

Upvotes: 1

Fabian Schultz
Fabian Schultz

Reputation: 18546

If you want to filter for name you can use .filter together with .startsWith or .indexOf to return true or false for a given user.

You've also set a new list of users on the onChange event, which results in an empty array sooner or later. Here I've used the user state that is only changed by the props, and a filteredUsers that is changed when a keystroke happened.

class Test extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      users: this.props.users,
      filteredUsers: this.props.users,
      q: ''
    };

    this.filterList = this.filterList.bind(this);
    this.onChange = this.onChange.bind(this);
  }

  componentWillReceiveProps(nextProps) {
    this.setState(
      {
        users: nextProps.users,
        filteredUsers: nextProps.users
      },
      () => this.filterList()
    );
  }

  onChange(event) {
    const q = event.target.value.toLowerCase();
    this.setState({ q }, () => this.filterList());
  }

  filterList() {
    let users = this.state.users;
    let q = this.state.q;

    users = users.filter(function(user) {
      return user.name.toLowerCase().indexOf(q) != -1; // returns true or false
    });
    this.setState({ filteredUsers: users });
  }

  render() {
    const userList = this.state.filteredUsers.map(user => {
      return <li>{user.name} {user.age}</li>;
    });

    return (
      <div>
        <input
          type="text"
          placeholder="Search"
          value={this.state.q}
          onChange={this.onChange}
        />
        <ul>
          {userList}
        </ul>
      </div>
    );
  }
}

const userList = [
  {
    name: 'Raul',
    age: 29
  },
  {
    name: 'Mario',
    age: 22
  }
];

ReactDOM.render(<Test users={userList} />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Upvotes: 5

Mayank Shukla
Mayank Shukla

Reputation: 104359

You need one more state variable to store the search result, initialise that variable by same data, once user type anything store the filtered data in that, Try this:

let users = [
  {
    name: 'Raul',
    age: 29
  },
  {
    name: 'Mario',
    age: 22
  }
];

class Test extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            users: users,
            result: users,
        };

        this.filterList = this.filterList.bind(this);

    }

    componentWillReceiveProps(nextProps) {

        this.setState({
            users: nextProps.users,            
        });

    }

    filterList(event) {
        let value = event.target.value;
        let users = this.state.users, result=[];
        result = users.filter((user)=>{
            return user.name.toLowerCase().search(value) != -1;
        });
        this.setState({result});
    }

  render(){

    const userList = this.state.result.map((user) => {
      return <li>{user.name} {user.age}</li>;
    });

    return(<div>
      <input type="text" placeholder="Search" onChange={this.filterList}/>
      <ul>
        {userList}
      </ul>
      </div>
    );

  }
}

ReactDOM.render(<Test/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>


<div id='app'></div>

Upvotes: 1

Doeke Norg
Doeke Norg

Reputation: 56

If you want to filter the list, you must have a criteria to filter against. For instance you have a variable let filterAge = 18;

In that case you can filter the userlist against that value using

let users = users.filter(function(user){
    //return all users older or equal to filterAge
    return user.age >= filterAge;        
});

Every result from the function that equals true, will be added to the users variable. A false return will leave it out. How you determine true / false is up to you. Hardcode it (not very useful), a simple equals statement (as above) or a function doing higher math. Your choice.

Upvotes: 0

Related Questions