1

I'm trying to setup filtering by checkbox in React.

What I want to happen is:

  1. User navigates to products where all products on displayed on page load.
  2. User selects checkbox and filtered products are displayed.
  3. De-selecting the checkbox will return all products again.

What currently happens is:

  1. User navigates to products, no products are displayed.
  2. User selects checkbox, filtered products are returned.
  3. Use deselects checkbox, all products are returned.

So it's nearly there, but something is missing for the initial page load, can anyone please advise what I've missed?

Example Data =

    console.log(checkedInputs) = Object { 35: true }
    console.log(Item) = Object { itemID: "5190", systemSku: "item", defaultCost: "78.95", avgCost: "78.95", discountable: "true", tax: "true", archived: "false", itemType: "default", serialized: "false", description: "item", … }Object { itemID: "5191", systemSku: "item", defaultCost: "142.95", avgCost: "142.95", discountable: "true", tax: "true", archived: "false", itemType: "default", serialized: "false", description: "item", … }

On initial page load checkedInputs =

console.log(checkedInputs = Object { })

Thanks!


Products.jsx

const Products = (props) => {
  const { Item } = props.items
  const { Category } = props.categories

  const [checkedInputs, setCheckedInputs] = useState({})

  const handleInputChange = (event) => {
    setCheckedInputs({ ...checkedInputs, [event.target.value]: event.target.checked })
  }

  useEffect(() => {
    console.log('Checked Inputs', checkedInputs)
  }, [checkedInputs])

  return (
    <Layout>
      <div className="flex mx-96">
        <div className="w-1/4">
          <ProductFilter category={Category} handleInputChange={handleInputChange} checkedInputs={checkedInputs} />
        </div>
        <div className="w-3/4">
          <div className="lg:grid grid-cols-3 gap-2 lg:my-12 lg:justify-center">
            {Item.map(item => {
              for (const [key, value] of Object.entries(checkedInputs)) {
                if (!checkedInputs || Object.keys(checkedInputs).every(value => checkedInputs[value] === false)) {
                  return <ProductCard item={item} key={item.itemID} />
                }
                if (value === true) {
                  if (item.categoryID === key) {
                    console.log(item)
                    return <ProductCard item={item} key={item.itemID} />
                  }
                }
              }
            })}
          </div>
        </div>
      </div>
    </Layout>
  )
}
3
  • can you share the data structure? (Item and checkedInputs) Commented Nov 21, 2020 at 16:13
  • Sure, I'll add it above. Commented Nov 21, 2020 at 16:33
  • it looks so difficult, items is an array of objects. every object add a property of display default true. when clicking on the checkbox, all product display converts to false except who is clicked. Commented Nov 21, 2020 at 20:34

2 Answers 2

1

Im not sure if this is the problem, but you I think you want to change

if (!checkedInputs || Object.keys(checkedInputs).every(value => checkedInputs[value] === false)) {
  return <ProductCard item={item} key={item.itemID} />
}

to

if (Object.keys(checkedInput).length < 1 || Object.keys(checkedInputs).every(value => checkedInputs[value] === false)) {
  return <ProductCard item={item} key={item.itemID} />
}

An empty object evaluates to true. I think an object will always evaluate to true. (Try Boolean({}) and Boolean({x:5})). Also, I am a bit confused (I could be missing something) as of why you are calling Object.keys(checkedInputs).every in every iteration of the Object.entries(checkedInputs). That value doesnt change right? So couldn't it be a static value you set before the looping?

Sign up to request clarification or add additional context in comments.

3 Comments

I get where your going with this answer, unfortunately it doesn't resolve the problem. I might not need to be doing that :)
Fixed it, with the order that you mentioned! Thank you!
And 'Object.keys(checkedInput).length < 1'
0
const Products = (props) => {
  const { Item } = props.items
  const { Category } = props.categories

  const [checkedInputs, setCheckedInputs] = useState({})

  const handleInputChange = (event) => {
    setCheckedInputs({ ...checkedInputs, [event.target.value]: event.target.checked })
  }

  useEffect(() => {
    console.log('Checked Inputs', checkedInputs)
  }, [checkedInputs])
  function renderItems(){
    let hasNoFilters = Object.keys(checkedInput).length < 1 || 
      Object.keys(checkedInputs).every(value =>checkedInputs[value] === false)
    if(hasNoFilters){
      // return everything if no filter
      return Item.map(item=>return <ProductCard item={item} key={item.itemID} />)
    }
    else{
      let filters = Object.keys(checkedInput).filter(itemID=>checkedInput[itemID] === true)
      return Item.map(item=>{
        //check to make sure itemID is found in filters
        let validItem = filters.find(itemID=>itemID === item.itemID)
        if(!validItem)
          return
        return <ProductCard item={item} key={item.itemID} />
      })
    }
  }  
  return (
    <Layout>
      <div className="flex mx-96">
        <div className="w-1/4">
          <ProductFilter category={Category} handleInputChange={handleInputChange} checkedInputs={checkedInputs} />
        </div>
        <div className="w-3/4">
          <div className="lg:grid grid-cols-3 gap-2 lg:my-12 lg:justify-center">
            {renderItems()}
          </div>
        </div>
      </div>
    </Layout>
  )
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.