Search code examples
javascriptreactjscheckboxfilteringarray-filter

How to checkbox filtering in reactjs and handle state? and show the available item after the checkbox


I want to make a filter system using multiple checkbox. But when i checked one checkbox it filter the state but when i unchecked it how i can get back the all data in state . Also if i select multiple checkbox then it will filter from the filtered item.

Here is my code.

state = {
  restaurant : [
     {name: 'La mesa', cuisine: ['italian', 'indian']},
     {name: 'Red Bull', cuisine: ['chiness', 'french']}
     {name: 'Purnima', cuisine: ['thai', 'arabic']}
  ]
  cuisine: [
    {id: 1, name: 'italian'},
    {id: 2, name: 'indian'},
    {id: 3, name: 'chiness'}
    {id: 4, name: 'french'},
    {id: 4, name: 'arabic'},
 ]
}

handleCuisineFilter = (e) => {
        if (e.target.checked) {
            const filter =
                this.state.restaurant.length &&
                this.state.restaurant.filter((rest) => rest.cuisine.includes(e.target.value));
            this.setState({ restaurant: filter });
        } else {
            Now when unchecked how i can get previous state???
        }
    };

render() {
  return (
<div>
   {this.state.cuisine.length && this.state.cuisine.map(
     cuisine=> (<li>
                   <input
                    id={cuisine.id}
                    type='checkbox'
                    onChange={this.handleCuisineFilter}
                    name='check'
                    value={cuisine.name}
                    />
              {cuisine.name }  {here will be count of number of restaurant}
               </li>
            ))}
     {this.state.restaurant.length && this.state.restaurant.map(rest=> <h5>rest.name</h5>)}
 </div>

I tried to explain best via my code . Help me please. Thank you in advance


Solution

  • You have to keep track of checked state for each filter and then filter against all filters at once every time.

    Here is the solution

    EDIT

    import React, { Component } from "react";
    import "./App.css";
    
    class App extends Component {
      state = {
        restaurant: [
          { name: "La mesa", cuisine: ["italian", "indian"] },
          { name: "Red Bull", cuisine: ["chiness", "french"] },
          { name: "Purnima", cuisine: ["thai", "arabic"] },
        ],
        // maintain a checked state for each filter
        cuisine: [
          { id: 1, name: "italian", checked: false },
          { id: 2, name: "indian", checked: false },
          { id: 3, name: "chiness", checked: false },
          { id: 4, name: "french", checked: false },
          { id: 5, name: "arabic", checked: false },
        ],
      };
    
      setFilter = (cuisine, flag) => {
        this.setState((prevState) => ({
          cuisine: prevState.cuisine.map((c) =>
            // check state for the selected cuisine
            c.id === cuisine.id ? { ...c, checked: flag } : c
          ),
        }));
      };
    
      handleCuisineFilter = (e, cuisine) => {
        if (e.target.checked) {
          this.setFilter(cuisine, true);
        } else {
          this.setFilter(cuisine, false);
        }
      };
    
      filterRestaurants = (restaurant) => {
        const checkedFilters = this.state.cuisine.filter((c) => c.checked);
        const noFiltersChecked = checkedFilters.length === 0;
    
        if (noFiltersChecked) {
          return true;
        } else {
          // EDITED:
          const tmp = checkedFilters.reduce(
            (hasRestaurantAllTheseCuisines, nextCuisine) =>
              (hasRestaurantAllTheseCuisines =
                hasRestaurantAllTheseCuisines &&
                restaurant.cuisine.includes(nextCuisine.name)),
            true
          );
    
          return tmp;
        }
      };
    
      render() {
        return (
          <div>
            {this.state.cuisine.length &&
              this.state.cuisine.map((cuisine) => (
                <li key={cuisine.id}>
                  <input
                    id={cuisine.id}
                    type="checkbox"
                    onChange={(e) => this.handleCuisineFilter(e, cuisine)}
                    name="check"
                    value={cuisine.name}
                  />
                  {cuisine.name} {/* here will be count of number of restaurant */}
                </li>
              ))}
            {/* Use .filter() with cuisine state */}
            {this.state.restaurant.length &&
              this.state.restaurant
                .filter(this.filterRestaurants)
                .map((rest) => <h5 key={rest.name}>{rest.name}</h5>)}
          </div>
        );
      }
    }
    
    export default App;
    

    Edited the code. The only change was the filter check here

    ...
    const tmp = checkedFilters.reduce(
      (hasRestaurantAllTheseCuisines, nextCuisine) =>
        (hasRestaurantAllTheseCuisines =
          hasRestaurantAllTheseCuisines &&
          restaurant.cuisine.includes(nextCuisine.name)),
      true
    );
    ...