How create multiple store filter in VueJS?

i'm new to VueJS and this is my first big project. In this project I have 2 filters for my elements, one is a search bar and the other is based on checkboxs. As you can see in my code, I have a computed propertie with 2 filters, the second filter is supposed to display the products with the same brand bu it doesn't work and I don't know why. If anybody have an idea it would be cool ;)

<div class="col-xs-12">
    <input type="text" v-model="search" placeholder="Rechercher" class="search">
</div>
<div class="row">
    <a href="#" v-on:click="show = !show" class="filter col-xs-3">+ filtres</a>
    <transition name="fade">
        <div v-if="show" class="filter__container">
            <ul>
                <li>
                    <input type="checkbox" v-model="getBrand" v-on:click="filtered" v-bind:value="brand" />
                    <label for="apple">Apple</label>
                </li>
                <li>
                    <input type="checkbox" v-model="getBrand" v-on:click="filtered" v-bind:value="brand" />
                    <label for="samsung">Samsung</label>
                </li>
            </ul>
        </div>
    </transition>
</div>
<div class="row between-xs no-margin grid">
    <div v-for="product in filtered" class="containers no-padding no-margin item">
        <router-link to="/items">
            <div @click="getProduct(product)">
                <img :src="product.img" :alt="product.alt" class="img">
                <div class="content">
                    <h3>{{ product.title }}</h3>
                    <p>{{ product.description }}</p>
                    <p>{{ product.brand }}</p>
                </div>
            </div>
        </router-link>
    </div>
</div>

<script>
import app from '../App'
import {mapActions} from 'vuex';

export default {
    components: {
        app
    },
    data() {
        return {
            show: false,
            search: '',
            brand: ['apple','samsung'],
            getBrand:[],
        }
    },
    computed: {
        products() {
            return this.$store.state.products;
        },
        filtered: function () {
            return this.products.filter((product) => {
                return product.title.toLowerCase().match(this.search.toLowerCase())
                return product.brand.match(this.getBrand.includes(brand))
            })
        },
    },
    methods: {
        ...mapActions([
            'currentProduct',
        ]),
        getProduct(product) {
            this.currentProduct(product);
        }
    },
};
</script>

export const store = new Vuex.Store({
  state: {
    products: [{
        img: '../icons/img.png',
        alt: 'logo',
        title: 'Title',
        description: 'Description',
        brand: 'Apple'
      },
      {
        img: '../icons/img.png',
        alt: 'logo',
        title: 'Title2',
        description: 'Description2',
        brand: 'Apple'
      },
      {
        img: '../icons/img.png',
        alt: 'logo',
        title: 'Title3',
        description: 'Description3'
        brand: 'Samsung'
      },
      {
        img: '../icons/img.png',
        alt: 'logo',
        title: 'Title4',
        description: 'Description4'
        brand: 'Samsung'
      }
    ],
    currentProduct: {},
  },
  getters: {
    getProduct: state => state.currentProduct,
  },
  mutations: {
    CURRENT_PRODUCT: (state, product) => {
      state.currentProduct = product;
    }
  },
  actions: {
    currentProduct: (context, product) => {
      context.commit('CURRENT_PRODUCT', product);
    }
  }
})

1 answer

  • answered 2019-10-15 15:00 skirtle

    You can't return twice from the same function. Either chain the conditions using && or chain in another call to filter.

    You're also misusing match. The argument needs to be a RegExp or something that can safely be converted to a RegExp. You can see the problem in the console if you type in a character like [ that has a special meaning in a RegExp. Perhaps you meant includes?

    The second condition also seems to be incorrect. Not entirely clear what that combination of match and includes is trying to achieve but I think you're looking for something like this:

    return this.products.filter((product) => {
        return product.title.toLowerCase().includes(this.search.toLowerCase()) &&
          this.getBrand.includes(product.brand)
    })
    

    It is worth noting that while both conditions are using a method called includes they are two different methods, one on a string and the other on an array.

    This also seems to be wrong:

    v-bind:value="brand"
    

    brand is an array of strings and you aren't looping over them with a v-for. Change it to value="Apple" and value="Samsung" instead, ensuring the case matches the data.

    I also suggest removing v-on:click="filtered". Not sure what that's trying to do but it seems to be treating a computed property as a click listener.