Vue JS Trying to filter between different tags and filter in items list

Viewed 37

In VueJS i have an array with plants in my store which looks like this:

  state: {
        query: '',
        tag: '',

        plants: [
          { 
            img: "https://cdn.webshopapp.com/shops/29478/files/361778137/650x650x2/hydroplant-monstera-obliqua.jpg",
             msg: 'Monstera',
            tags: 'easy'},
          {
            img: "https://mevrouwmonstera.nl/wp-content/uploads/2020/05/Aloe-ferox.jpg",
            msg: 'Aloe vera',
            tags: 'easy'},
          {
            img: "https://www.plantje.nl/wp-content/uploads/2022/04/bonsai-ficus-51024.jpg",
            msg: 'Bonsai',
            tags: 'hard'},
          { 
            img: "https://images.prismic.io/rbnl/0737820a-d068-4588-8898-1c168f49a15d_cactus-plant-in-pot.jpg?auto=compress,format&rect=0,0,1000,1000&w=500&h=500",
            msg: 'Cactus',
            tags: 'easy'},
        ],

  },

It has msg, on which i filter and tags (easy and hard). I can filter between the names of the plants if I type letters in my input field. Now when I select one of the tags I want the plants with that tag to also be displayed. I want these filters to work in one function so I can filter both these things at the same time. Only the filter of msg is working.

The code in my SearchComponent looks like this:

<template>
    <div id="app">
      <div>
        
        <form action="#">
      <label for="lang">filter between tags:</label>
      <select v-model="selected" name="plants" id="lang">
    
        <option class="item plant" v-for="tag in filteredTags" :key="tag" :value="tag">{{tag}}</option>
      </select>
      <input type="submit" value="Submit" @click="filteredList"/>
        </form>


          <input type="text" v-model="query" placeholder="Search plants..." />
        <div v-for="(plants, index) in $store.state.plants" :key="index">
        
        <div class="item plant" v-for="plant in filteredList" :key="plant.msg">         

            <img v-bind:src= "plant.img" /> 
            <p>{{ plant.msg }}</p> 
            <button @click="deletePlants(index)">
            Delete plant
          </button>
          </div>
        </div>
      </div>
      <div class="item error" v-if="query && !filteredList.length">
          <p>No results found!</p>
      </div>


    </div>
  </template>
  
  <script>
    import { mapMutations, mapGetters } from 'vuex'
    
  export default {
    name: 'SearchComponent',
    props: {
        msg: String
    },

    data () {
        return {
            selected: null
        }
    },

    computed: {

        ...mapGetters([
      'filteredList',
      'filteredTags',
      'filteredTags2'
      // ...
    ]),
        query: {
            set (value) {
                this.setQuery(value);
            },

            get () {
                return this.$store.state.query;
            }
        },

        tag: {
            set (value) {
                this.setTag(value);
            },

            get () {
                return this.$store.state.tag;
            }
        },

    
        
      },

      methods: {
        ...mapMutations([
             'setQuery',
             'deletePlants',
             'setTag'
             ]),

        
      }
  };
  </script>

In my store this is the code I havr for the getters and mutations to filter

 mutations: {

    setQuery(state, value ) {
        state.query = value;
    },

    setTag (state, value) {
        state.tag = value
    },

    addPlants(state, plant) { state.plants.push({ msg: plant }) },

    deletePlants (state, index){
        state.plants.splice(index, 1);
    },
  },

  getters: {

  filteredList (state) {
    return state.plants.filter((item) => {
        return item.msg.toLowerCase().indexOf(state.query.toLowerCase()) !== -1 && item.tags.toLowerCase().indexOf(state.tag.toLowerCase()) !== -1
        })
  },

  filteredTags (state) {
    //todo filter tags and remove duplicates

    return Array.from(new Set(state.plants.map( (x) => x.tags)));

  }

I want to Use the getter filteredList to be able to filter both these things at one but right now I can still only filter the msg. I also get the following error:

TypeError: handler.apply is not a function

When I try to push the submit button. Can anyone help me with this problem? I also put the code on codesandbox.io: https://codesandbox.io/p/github/michafvdw/plant-searcher/csb-b192tb/plant-searcher?file=%2FREADME.md

1 Answers

I solved the problem by changing the following.

In my searchcomponent I had this:

<form action="#">
      <label for="lang">filter between tags:</label>
      <select v-model="selected" name="plants" id="lang">
    
        <option class="item plant" v-for="tag in filteredTags" :key="tag" :value="tag">{{tag}}</option>
      </select>
      <input type="submit" value="Submit" @click="filteredList"/>
        </form>

I changed that to the following:

<select v-model="tag" name="plants" id="lang">
        <option disabled value="">Please select one</option>
        <option class="item plant" v-for="tag in filteredTags" :key="tag" :value="tag">{{tag}}</option>

        </select>

Using the submit button to go to filteredList was wrong. But now it's working

Related