0

I am trying to filter the list of items in state.items by adding items from state.filterItems to my state.filter array

if I use this.state.items.filter(items => items.cat === 'veg' ) of course this works but I need to be able to filter dynamically using the list of items added to my state.filter array and I'm not sure how to do this,

I would also like to be able select multiple options and then hit a button to apply the filters rather than selecting them one by one

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

Hello.js

import React, { Component } from 'react';
import logo from './logo.svg'
import './App.css'
import update from 'immutability-helper'
import TodoList from './TodoList'
import styled from 'styled-components'
import FilterList from './FilterList'

const Wrapper = styled.div`
  max-width:1280px;
  background: papayawhip;
  margin: 0 auto;
  padding:20px;
`

const Grid = styled.div`
  display:flex;
  flex-wrap:wrap;
`

const Cell = styled.div`
  flex: 0 0 25%;
  padding: 20px;
`

export default class hello extends Component {
  constructor(props) {
    super(props)
    this.state = {
      items: [
        {id: 1, cat: 'fruit', text: 'apples'},
        {id: 2, cat: 'fruit', text: 'oranges'},
        {id: 3, cat: 'fruit', text: 'peaches'},
        {id: 4, cat: 'veg', text: 'carrots'},
        {id: 5, cat: 'veg', text: 'aubergine'},
        {id: 6, cat: 'veg', text: 'peaches'},
        {id: 7, cat: 'bread', text: 'olive bread'},
        {id: 8, cat: 'bread', text: 'bread roll'},
        {id: 9, cat: 'bread', text: 'bagel'},
      ],
      filterItems: [
        {id: 1, text: 'bread'},
        {id: 2, text: 'fruit'},
        {id: 3, text: 'vegetables'},
      ],
      filter: [
        {text: 'bread'}
      ],
    }
  }

  handleFilterChange = (filter) => {
    this.setState({filter: filter})
  }

  render() {
    return (
      <Wrapper>
        <div>
        <FilterList
          value={this.state.filter}
          onChange={this.handleFilterChange}
          filterItems={this.state.filterItems}
        />
        </div>
        <Grid>
          {
            this.state.items.filter(items => items.cat === 'veg', 'fruit' )
            .map(item =>
              <Cell>
                {console.log(this.state.filter.text)}
                <div>{item.cat}</div>
                <div>{item.text}</div>
              </Cell>
            )
          }
        </Grid>
      </Wrapper>
    )
  }
}

//  <pre>{JSON.stringify(this.state, null, 4)} </pre>

FilterList.js

import React, { Component } from 'react';
import TodoItem from './TodoItem'
import update from 'immutability-helper'
import styled from 'styled-components'

const FilterListBg = styled.div`
  background: lightblue;
  width: 100%;
  height: 60px;
`

const FilterListItem = styled.div`
  float: left;
  height: 40px;
  width: 100px;
  padding:10px;
  border-right: 1px solid #ff00ff;
`

const FilterBg = styled.div`
  width: 100%;
  height:40px;
  background: #fff;
  margin-top:20px;
`

const FilterItem = styled.div`
  float: left;
  height: 40px;
  width: 100px;
  padding:10px;
  border-right: 1px solid #ff00ff;
`
export default class FilterList extends Component {
  constructor() {
    super()

    this.state = {
      search: ''
    }
  }
  handleAdd = (item) => {
      const value = update(this.props.value, {
          $push: [
            {
            text: item,
            id: Math.random(),
            }
          ]
      })
      this.props.onChange(value)
    }

  handleRemove = (index) => {
      const value = update(this.props.value, {
        $splice: [
          [index, 1]
        ]
      })
      this.props.onChange(value)
    }

  handleFilterUpdate = event => {
    this.setState({ search: event.target.value })
  }

  render() {
    return (
      <div>
        <input
          type="text"
          value={this.state.search}
          onChange={this.handleFilterUpdate}
          placeholder="Hledat podle nazvu"
        />
        {this.state.search}
        <FilterListBg>
          {
            this.props.filterItems.filter(items => items.text.toLowerCase().indexOf(this.state.search.toLowerCase()) >= 0)
            .map((item,cat,index) =>
              <FilterListItem key={item.id} onClick={()=>this.handleAdd(item.text)}>
                {item.text}
              </FilterListItem>
            )
          }
        </FilterListBg>
        Aktivní filtry
        <FilterBg>
          {
            this.props.value.map((item, index) =>
            <FilterItem key={item.id} onClick={this.handleRemove}>
              {item.text}
            </FilterItem>
            )
          }
        </FilterBg>

      </div>
    )
  }
}

1 Answer 1

1

Assuming you want to show the items matching your filterList, shouldn't something simple like this work?

const filterTexts = this.state.filter.map(item => item.text);
const itemsToShow = this.state.items.filter(
                      item => filterTexts.indexOf(item.cat) !== -1);

And then you can map over itemsToShow to create your Cells.

If you want a one-liner to simply copy-paste:

this.state.items.filter(items => this.state.filterItems.map(item => item.text)
                          .indexOf(items.cat) !== -1 )
    .map(item =>
        <Cell>
            {console.log(this.state.filter.text)}
            <div>{item.cat}</div>
            <div>{item.text}</div>
        </Cell>
    )
Sign up to request clarification or add additional context in comments.

10 Comments

thanks for the reply! Yes I want to show the items in my state.filter that match the items in state.filterList once they've been added to state.filter. I have added this to my webpackbin and it doesn't seem to filter by what's selected
Can you try using the first solution where the lists are saved as variables first, then console.log those and tell me what the output is?
in filterTexts = (3) ["bread", "fruit", "vegetables"] 0 : "bread" 1 : "fruit" 2 : "vegetables" length : 3 __proto__ : Array(0)
itemsToShow = (6) [{…}, {…}, {…}, {…}, {…}, {…}] 0 : {id: 1, cat: "fruit", text: "apples"} 1 : {id: 2, cat: "fruit", text: "oranges"} 2 : {id: 3, cat: "fruit", text: "peaches"} 3 : {id: 7, cat: "bread", text: "olive bread"} 4 : {id: 8, cat: "bread", text: "bread roll"} 5 : {id: 9, cat: "bread", text: "bagel"} length : 6 __proto__ : Array(0)
Is this not the desired functionality? You now have a list of all items that matched the filter, and you can run your map() function on it to create your JSX elements. As a sidenote, you have called it vegetables in the filters and veg in the items.cat. You'll either have to choose one and stick with it or write some logic to map from one to the other. I can help with that if you want to keep them different for some reason.
|

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.