Filter The List Using Multiple CheckBoxes in React Js

Viewed 16001

Hello guys i am trying to filter the list of array of objects onClick of the checkbox based on a condition, but my else condition in handle method's is returning me a same array the state doesn't change,so i want default list that is remove filtered list when i try to uncheck the checkbox on all of it.

import React from "react";
import "./Search.css";

class Search extends React.Component {
  constructor() {
    super();
    this.state = {
      searchLists: [
        {
          id: 1,
          type: "All",
          name: "Akash",
          location: "bangalore",
          experience: 1
        },
        {
          id: 2,
          type: "FullTime",
          name: "feroz",
          location: "mumbai",
          experience: 3
        },
        {
          id: 3,
          type: "PartTime",
          name: "Farheen",
          location: "agra",
          experience: 5
        },
        {
          id: 4,
          type: "Freelancer",
          name: "Raju",
          location: "chennai",
          experience: 6
        },
        {
          id: 5,
          type: "All",
          name: "Asif",
          location: "vegas",
          experience: 7
        }
      ],
      checked: false
    };
  }

  handleAll = () => {
    console.log("i clicked");
    if (this.state.checked === false) {
      const filteredAll = this.state.searchLists.filter(
        item => item.type === "All"
      );

      console.log(filteredAll);
      this.setState({ searchLists: filteredAll, checked: true });
    } else {
      setTimeout(() => {
        this.setState({
          searchLists: this.state.searchLists,
          checked: false
        });
      }, 10000);
    }
  };

  handleFullTime = () => {
    if (this.state.checked === false) {
      const filteredFullTime = this.state.searchLists.filter(
        item => item.type === "FullTime"
      );
      console.log(filteredFullTime);
      this.setState({ searchLists: filteredFullTime, checked: true });
    } else {
      setTimeout(() => {
        this.setState({
          searchLists: this.state.searchLists,
          checked: false
        });
      }, 10000);
    }
  };

  handlePartTime = () => {
    if (this.state.checked === false) {
      const filteredPartTime = this.state.searchLists.filter(
        item => item.type === "PartTime"
      );
      console.log(filteredPartTime);
      this.setState({ searchLists: filteredPartTime, checked: true });
    } else {
      setTimeout(() => {
        this.setState({
          searchLists: this.state.searchLists,
          checked: false
        });
      }, 10000);
    }
  };

  handleFreelancer = () => {
    if (this.state.checked === false) {
      const filteredFreelancer = this.state.searchLists.filter(
        item => item.type === "Freelancer"
      );
      console.log(filteredFreelancer);
      this.setState({ searchLists: filteredFreelancer, checked: true });
    } else {
      setTimeout(() => {
        this.setState({
          searchLists: this.state.searchLists,
          checked: false
        });
      }, 10000);
    }
  };

  render() {
    console.log("rendered");
    const mapped = this.state.searchLists.map(item => {
      return (
        <div key={item.id}>
          <li>
            {item.name}
            {item.type}
          </li>
        </div>
      );
    });
    return (
      <div className="searchContainer">
        <form>
          <label htmlFor="myInput">All</label>
          <input
            id="myInput"
            type="checkbox"
            onClick={this.handleAll}
            checked={this.state.checked}
          />
          <label htmlFor="myInput">FullTime</label>
          <input id="myInput" type="checkbox" onClick={this.handleFullTime} />
          <label htmlFor="myInput">PartTime</label>
          <input id="myInput" type="checkbox" onClick={this.handlePartTime} />
          <label htmlFor="myInput">Freelancer</label>
          <input id="myInput" type="checkbox" onClick={this.handleFreelancer} />
        </form>
        <ul style={{ marginLeft: "70px" }}>{mapped}</ul>
      </div>
    );
  }
}

export default Search;


here is the link to my code https://codesandbox.io/s/eloquent-brattain-orv76?file=/src/Search.js

3 Answers

Do not override your state with filtered results. As of right now, your search results gets replaced with filtered array each time you click checkbox. I would add filter property to your state to hold currently selected filter and use it during render.

I would suggest refactoring your code to simplify logic and get rid of timeouts, its makes your app to appear unresponsive.

this.state ={
  filter: 'none',
  searchList: [...]
}

//unify all checkboxes to share logic, e holds information about event that triggered this function, we will add value to each checkbox for easy access
handleCheckbox = e => {
  if (this.state.filter === e.target.value) this.setState({ filter: "none" });
  else this.setState({ filter: e.target.value, checked: true });
};

//mapped variable will handle filtering results, if `state.filter` matches `item.type` item will be rendered, also if filter is set to none, all items are rendered, this will not preserve multiple filters though,
const mapped = const mapped = this.state.searchLists.map(item => {
      if (item.type === this.state.filter || this.state.filter === "none")
        return (...)

//lastly change inputs to pass filters
  <input
    id="myInput"
    value="PartTime"
    type="checkbox"
    onClick={this.handleCheckbox}
  />

Check if this works as expected: https://codesandbox.io/s/vibrant-meadow-9k8u7?file=/src/Search.js:1968-2111

The checked state is not valid. We should store it as an array and push/pop the checked/unchecked items from it.

https://codesandbox.io/s/upbeat-ramanujan-b2jui

import React from "react";
import "./Search.css";

class Search extends React.Component {
  constructor() {
    super();
    this.state = {
      filterList: [
        {
          id: 11,
          name: "Part Time",
          value: "PART_TIME"
        },
        {
          id: 12,
          name: "Full Time",
          value: "FULL_TIME"
        },
        {
          id: 13,
          name: "Freelancer",
          value: "FREELANCER"
        }
      ],
      searchLists: [
        {
          id: 1,
          type: "PART_TIME",
          name: "Akash",
          location: "bangalore",
          experience: 1
        },
        {
          id: 2,
          type: "PART_TIME",
          name: "feroz",
          location: "mumbai",
          experience: 3
        },
        {
          id: 3,
          type: "FULL_TIME",
          name: "Farheen",
          location: "agra",
          experience: 5
        },
        {
          id: 4,
          type: "FREELANCER",
          name: "Raju",
          location: "chennai",
          experience: 6
        },
        {
          id: 5,
          type: "FULL_TIME",
          name: "Asif",
          location: "vegas",
          experience: 7
        }
      ],
      activeFilter: []
    };
  }

  onFilterChange(filter) {
    const { filterList, activeFilter } = this.state;
    if (filter === "ALL") {
      if (activeFilter.length === filterList.length) {
        this.setState({ activeFilter: [] });
      } else {
        this.setState({ activeFilter: filterList.map(filter => filter.value) });
      }
    } else {
      if (activeFilter.includes(filter)) {
        const filterIndex = activeFilter.indexOf(filter);
        const newFilter = [...activeFilter];
        newFilter.splice(filterIndex, 1);
        this.setState({ activeFilter: newFilter });
      } else {
        this.setState({ activeFilter: [...activeFilter, filter] });
      }
    }
  }

  render() {
    const { filterList, activeFilter } = this.state;
    let filteredList;
    if (
      activeFilter.length === 0 ||
      activeFilter.length === filterList.length
    ) {
      filteredList = this.state.searchLists;
    } else {
      filteredList = this.state.searchLists.filter(item =>
        this.state.activeFilter.includes(item.type)
      );
    }
    return (
      <div className="searchContainer">
        <form>
          <label htmlFor="myInput">All</label>
          <input
            id="myInput"
            type="checkbox"
            onClick={() => this.onFilterChange("ALL")}
            checked={activeFilter.length === filterList.length}
          />
          {this.state.filterList.map(filter => (
            <React.Fragment>
              <label htmlFor={filter.id}>{filter.name}</label>
              <input
                id={filter.id}
                type="checkbox"
                checked={activeFilter.includes(filter.value)}
                onClick={() => this.onFilterChange(filter.value)}
              />
            </React.Fragment>
          ))}
        </form>
        <ul style={{ marginLeft: "70px" }}>
          {filteredList.map(item => (
            <div key={item.id}>
              <li>
                {item.name} -- {item.type}
              </li>
            </div>
          ))}
        </ul>
      </div>
    );
  }
}

export default Search;

Here I used cuisines for my checkbox items. The following code snippet gives the logic for checkbox filtering. handleCuisineChange is the function that contains the logic. The length of for loop is 8 since the number of cuisines (the number of checkbox items) I have taken here is 8. Replace the cuisines here with your checkbox data. Apply this logic and your checkbox items are ready for filtering.

Inside axios I used my own backend API and port number.

handleCuisineChange=(cuisine_id)=>
    {
        const {cuisineArray}=this.state; //an empty array declared in constructor
       
        if (cuisineArray.indexOf(cuisine_id) == -1)
        {
            cuisineArray.push(cuisine_id);
        }
        else
        {
            var index=cuisineArray.indexOf(cuisine_id);
            cuisineArray.splice(index,1);
        }    

        const {cuisineArray2}=this.state; //an empty array declared in constructor
        let i=0;
        for (i=0;i<8;i++)
        {
            if(cuisineArray[i]==undefined)
            {
                cuisineArray2[i]=cuisineArray[0];
            }
            else
            {
                cuisineArray2[i]=cuisineArray[i];
            }
        }

        this.props.history.push(`/checking3?cuisine_id1=${cuisineArray2[0]}&cuisine_id2=${cuisineArray2[1]}&cuisine_id3=${cuisineArray2[2]}&cuisine_id4=${cuisineArray2[3]}&cuisine_id5=${cuisineArray2[4]}&cuisine_id6=${cuisineArray2[5]}&cuisine_id7=${cuisineArray2[6]}&cuisine_id8=${cuisineArray2[7]}`);
        let filterObj={cuisine_id1:cuisineArray2[0],cuisine_id2:cuisineArray2[1],cuisine_id3:cuisineArray2[2],cuisine_id4:cuisineArray2[3],cuisine_id5:cuisineArray2[4],cuisine_id6:cuisineArray2[5],cuisine_id7:cuisineArray2[6],cuisine_id8:cuisineArray2[7]};
        axios(
            {
                method:'POST',
                url:`http://localhost:7000/getCuisine`,
                headers:{'Content-Type':'application/json'},
                data:filterObj
            }
        )
        .then(res=>
            {
                this.setState({restaurants:res.data.restaurants});
            })
        .catch(err=>console.log(err))
    }

render()
    {
        const {restaurants}=this.state;
        return(
            
                <div>
                   
                            <input type="checkbox" name="cuisines" id={"1"} onChange={(event) => this.handleCuisineChange("1")}  />
                            <span className="checkbox-items" > North Indian </span> <div style={{display: "block"}}> </div>
                            <input type="checkbox" name="cuisines"  id={"2"} onChange={(event) => this.handleCuisineChange("2")}  />
                            <span className="checkbox-items" > south indian </span> <div style={{display: "block"}}> </div>
                            <input type="checkbox" name="cuisines" id={"3"} onChange={(event) => this.handleCuisineChange("3")}  />
                            <span className="checkbox-items" > chinese </span> <div style={{display: "block"}}> </div>
                            <input type="checkbox" name="cuisines" id={"4"} onChange={(event) => this.handleCuisineChange("1")}  />
                            <span className="checkbox-items" > fast food </span> <div style={{display: "block"}}> </div>
                            <input type="checkbox" name="cuisines" id={"5"} onChange={(event) => this.handleCuisineChange("1")}  />
                            <span className="checkbox-items" > Street food </span> <div style={{display: "block"}}> </div>
                            <input type="checkbox" name="cuisines" id={"6"} onChange={(event) => this.handleCuisineChange("1")}  />
                            <span className="checkbox-items" > American </span> <div style={{display: "block"}}> </div>
                            <input type="checkbox" name="cuisines" id={"7"} onChange={(event) => this.handleCuisineChange("1")}  />
                            <span className="checkbox-items" > Italian </span> <div style={{display: "block"}}> </div>
                            <input type="checkbox" name="cuisines" id={"8"} onChange={(event) => this.handleCuisineChange("1")}  />
                            <span className="checkbox-items" > Mexican </span> <div style={{display: "block"}}> </div>
                </div>
       )
  } //render end

Related