7

I have 2 buttons which when clicked should filter by novelty or offer , I am able to make it so that when novelty is clicked it will filter by this but I am unable to make it so that if both are click it will filter by both novelty and offer

How can I make it so that when both novelty and offer are clicked it will filter by both of these?

https://www.webpackbin.com/bins/-KpVGNEN7ZuKAFODxuER

import React from 'react'

export default class extends React.Component {
  constructor() {
    super()

    this.state = {
      products: [
        { id: 1, novelty: true, offer: false, name: 'test1' },
        { id: 2, novelty: true, offer: true, name: 'test2' },
        { id: 3, novelty: false, offer: true, name: 'test3' } 
        ],
      display: 'all',
      filters: [
        {novelty:'true'},
        {offer: 'true'}
      ]
    }
  }

  setCategory (category) {
    this.setState({
      display: category 
    });
  }

 render() {
   return(
   <div>
      <button onClick={()=>this.setCategory(true)}>Akce</button>
      <button onClick={()=>this.setCategory(true)}>Offer</button>
           {
      this.state.products.filter( product => 
       products.offer === this.state.display ||
        this.state.display==='all')
        .map(product =>
         <div>{product.name}</div>
           )
            }
   </div>
    )
  }
}
2
  • The link you provided doesn't work... Commented Jul 20, 2017 at 13:47
  • works for me, but have updated the link Commented Jul 20, 2017 at 13:53

1 Answer 1

12

Here is the final version I've come up with:

import React from 'react'

export default class extends React.Component {
  constructor() {
    super()

    this.state = {
      products: [
        { id: 1, novelty: true, offer: false, name: 'test1' },
        { id: 2, novelty: true, offer: true, name: 'test2' },
        { id: 3, novelty: false, offer: true, name: 'test3' } 
        ],
      filters: {
        novelty: true,
        offer: true
      }
    }
  }

  setCategory (category) {
    this.setState((state) => ({
      filters: Object.assign({}, state.filters, { [category]: !state.filters[category] })
    }));
  }

 render() {
   console.log(this.state.filters)
   return(
   <div>
      <button onClick={()=>this.setCategory('novelty')}>Akce</button>
      <button onClick={()=>this.setCategory('offer')}>Offer</button>
           { this.state.products
                       .filter(product => product.novelty === this.state.filters.novelty || product.offer === this.state.filters.offer)
                       .map(product =>
             <div key={product.id}>{product.name}</div>
           )}
   </div>
    )
  }
}

https://www.webpackbin.com/bins/-KpVHqfkjeraq6pGvHij

A few things:

  • Using a boolean instead of a string in your case is more adapted. (true instead of 'true').
  • display: 'all' isn't required for your use case. You can compute this value from your filters if you need to.
  • setCategory receive which category you want to set as a param.
  • I would rename setCategory to setFilter

Also, I'm using the asycnhronous version of setState. This allows you to hand in a function.

this.setState((state) => ({
      filters: Object.assign({}, state.filters, { [category]: !state.filters[category] })
}));

Here I'm using Object.assign to create a new Object. I populate him with state.filters and finally I update the filter you want to. category will either be novelty or offer and thanks to that I'm using the shorthand version of [category].

To conclude, I also update your filter function to check the product.novelty against the filter.novelty or the product.offer with the filter.offer

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

6 Comments

this is great! exactly what I was after and thank you for taking the time to explain everything so clearly!
Beat me to it. I got hung up on the object assign, but besides that our code was identical.
Is it possible to display all items if novelty and offer are both false, it will display the items if one of the fields === true but won't show otherwise
@Chad yep me too. At first I wrote filters: { ...state.filters, { [category]: !state.filters[category] } } but then saw it was not supporting this ES6 syntax. So Object.assign ;)
@tomharrison hmm maybe something like this: .filter(product => (!this.state.filters.novelty || ( this.state.filters.novelty && product.novelty)) && (!this.state.filters.offer || (this.state.filters.offer && product.offer))) (not tested though.. but what you want is, if the filter is true, then check if the product is true too. If the filter is false, then let the product pass anyway). Can be improved I'm pretty sure, just play around ;)
|

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.