Home > Software engineering >  Need a solution to filter products by multiple price ranges
Need a solution to filter products by multiple price ranges

Time:05-27

I am new in VueJS. I have a list of products, and I want to filter those products by price range. so, I built a component (filter-sidebar) that's a sidebar containing filter types (price, brand.. etc) by radio buttons, I want to filter product prices, and the products with a selected price range will be displayed in the parent component.

&& If there's another better method to filter I will be happy :)

{
    "products":[
        {
            "id":1,
            "name": "Apple Watch Series 5",
            "price": 339.99,
            "rating": 4,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/1.3b312012.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"            },
        {
            "id":2,
            "name": "Apple iPhone 11 (64GB, Black)",
            "price": 669.99,
            "rating": 5,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/2.1aba2cea.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":3,
            "name": "Apple iMac 27-inch",
            "price": 999.99,
            "rating": 4,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/3.29c766f8.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":4,
            "name": "OneOdio A71 Wired Headphones",
            "price": 49.99,
            "rating": 3,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/4.73f34744.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":5,
            "name": "Apple - MacBook Air® (Latest Model) - 13.3 Display - Silver",
            "price": 999.99,
            "rating": 4,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/5.c5b188e5.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":6,
            "name": "Switch Pro Controller",
            "price": 429.99,
            "rating": 3,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/6.833c8951.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":7,
            "name": "Google - Google Home - White/Slate fabric",
            "price": 129.29,
            "rating": 4,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/1.3b312012.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "google"
        },

Child Component (filter-sidebar):

<template>
    <div >
        <h5 >Filters</h5>
        <div >
          <h5 >Multi Range</h5>
          <div >
            <div >
              <label for="all">
                <input
                  id="all"
                  type="radio"
                  value="all"
                  name="price"
                  v-model="selectPrice"
                  
                  @change="filterRangePrice()"
                  checked
                />
                All</label
              >
            </div>
            <div >
              <label for="10">
                <input
                  id="10"
                  type="radio"
                  value="10"
                  name="price"
                  v-model="selectPrice"
                  
                  @change="filterRangePrice()"
                />
                &lt;= $10</label
              >
            </div>
            <div >
              <label for="10-100">
                <input
                  id="10-100"
                  type="radio"
                  value="10-100"
                  name="price"
                  v-model="selectPrice"
                  
                  @change="filterRangePrice()"
                />
                $10 - $100</label
              >
            </div>
            <div >
              <label for="100-500">
                <input
                  id="100-500"
                  type="radio"
                  name="price"
                  
                  value="100-500"
                  v-model="selectPrice"
                  @change="filterRangePrice()"
                />
                $100 - $500</label
              >
            </div>
            <div >
              <label for="500">
                <input
                  id="500"
                  type="radio"
                  
                  value="500"
                  name="price"
                  v-model="selectPrice"
                  @change="filterRangePrice()"
                />
                &gt;= $500</label
              >
            </div>
          </div>
</template>

<script>
export default {
  name: "FilterSidebar",

  data() {
    return {
      selectPrice: null,
    };
  },

  methods: {
    filterRangePrice() {
      this.$emit("filterPrice", this.selectPrice);
    }
  }
};
</script>

Parent Component:

<template>

  <div>
    <filter-sidebar @filter-price="filterByPrice" />
  </div>

 <div  v-if="layout === 'grid'">
      <div
        v-for="prod of (handleRangePrice, filterProducts.slice(0, 7))"
        :key="prod.id"
        
      >
        <div >
          <div >
            <a href="#">
              <img :src="prod.img" :alt="prod.name"  />
            </a>
          </div>

          <div >
            <ul>
              <li><span > star </span></li>
              <li><span > star </span></li>
              <li><span > star </span></li>
              <li>
                <span > star_border </span>
              </li>
            </ul>
          </div>

          <h5 >${{ prod.price }}</h5>
          <div >
            <h4 >{{ prod.name }}</h4>
            <p >{{ prod.discription }}</p>
          </div>
        </div>

        <div >
          <a href="#" >
            <span > favorite_border </span>
            <span>Wishist</span>
          </a>
          <a href="#" >
            <span > shopping_cart </span>
            <span>View In Cart</span>
          </a>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
import FilterSidebar from "./FilterSidebar.vue";

export default {
  name: "search-bar",
  components: {
    FilterSidebar,
  },

  data() {
    return {
      productData: require("@/data/store-data.json"),
      selectedPrice: null,
     
    };
  },

  computed: {
    filterProducts: function () {
      let realProducts = this.productData.products;
      if (this.searchValue != "" && this.searchValue) {
        return realProducts.filter((prod) => {
          return prod.name
            .toLowerCase()
            .includes(this.searchValue.toLowerCase());
        });
      }
      return realProducts;
    },

    // return filtered products by price
    handleRangePrice: function () {
      let allProducts = this.productData.products;
      if (this.selectedPrice) {
        switch (this.selectedPrice) {
          case "all":
            allProducts;
            break;

          case "10":
            allProducts = allProducts.filter((item) => {
              item.price <= this.selectedPrice;
            });
            break;

          case "10-100":
            allProducts = allProducts.filter((item) => {
              item.price <= 100 && item.price >= 10;
            });
            break;

          case "100-500":
            allProducts = allProducts.filter((item) => {
              item.price <= 500 && item.price >= 100;
            });
            break;

          case "500":
            allProducts = allProducts.filter((item) => {
              item.price >= this.selectedPrice;
            });
            break;
        }
      }
      return allProducts;
    },
},

 methods: {
    filterByPrice: function (price) {
      this.selectedPrice = price;
    },
  },
};
</script>

CodePudding user response:

Another way, please take a look:

Vue.component('FilterSidebar', {
  template: `
  <div >
    <h5 >Filters</h5>
    <div >
      <h5 >Multi Range</h5>
      <div >
        <div  v-for="range in ranges" :key="range.lbl">
          <label :for="range.lbl">
            <input :id="range.lbl" type="radio" :value="{min: range.min, max: range.max}"
              name="price" v-model="selectPrice" 
              @change="filterRangePrice" />
            {{range.lbl}}</label
          >
        </div>
      </div>
    </div>
  </div>
  `,
  data() {
    return {
      selectPrice: {min: 0, max: 1000000},
      ranges: [{lbl: 'All', min: 0, max: 1000000}, {lbl: '<=$10', min: 0, max: 10}, {lbl: '$10 - $100', min: 10, max: 100}, {lbl: '$100 - $500', min: 100, max: 500}, {lbl: '>=500', min: 500, max: 1000000}]
    };
  },
  methods: {
    filterRangePrice() {
      this.$emit("filter-price", this.selectPrice);
    }
  }
})

new Vue({
  el: '#demo',
  data() {
    return {
      productData: {"products":[{"id":1, "name": "Apple Watch Series 5", "price": 339.99, "rating": 4, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/1.3b312012.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":2, "name": "Apple iPhone 11 (64GB, Black)", "price": 669.99, "rating": 5, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/2.1aba2cea.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":3, "name": "Apple iMac 27-inch", "price": 999.99, "rating": 4, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/3.29c766f8.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":4, "name": "OneOdio A71 Wired Headphones", "price": 49.99, "rating": 3, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/4.73f34744.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":5, "name": "Apple - MacBook Air® (Latest Model) - 13.3 Display - Silver", "price": 999.99, "rating": 4, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/5.c5b188e5.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":6, "name": "Switch Pro Controller", "price": 429.99, "rating": 3, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/6.833c8951.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":7, "name": "Google - Google Home - White/Slate fabric", "price": 129.29, "rating": 4, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/1.3b312012.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "google"},]},
      selectedPrice: null,
      layout: 'grid', 
      filteredData: [],
      searchValue: ''
    };
  },
  methods: {
    filterByPrice(price) {
      this.selectedPrice = price
      if (this.selectedPrice) {
        this.filteredData =  this.productData.products.filter(item => 
          item.price >= price.min && item.price <= price.max
        );
      } else this.filteredData = this.productData.products
    },
    filterProducts() {
      if (this.searchValue != "" && this.searchValue) {
        this.filteredData = this.productData.products.filter((prod) => {
          return prod.name
            .toLowerCase()
            .includes(this.searchValue.toLowerCase());
        });
      }
    },
  },
  mounted() {
    this.filteredData = [...this.productData.products]
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://fonts.googleapis.com/css?family=Material Icons|Material Icons Outlined|Material Icons Two Tone|Material Icons Round|Material Icons Sharp" rel="stylesheet">
<div id="demo">
  <div>
    <input v-model="searchValue" @input="filterProducts" />
    <filter-sidebar @filter-price="filterByPrice"></filter-sidebar>
  </div>
  <div  v-if="layout === 'grid'">
    <div v-for="prod in filteredData" :key="prod.id" >
      <div >
        <div >
          <a href="#"><img :src="prod.img" :alt="prod.name"  /></a>
        </div>
        <div >
          <ul>
            <li><span > star </span></li>
            <li><span > star </span></li>
            <li><span > star </span></li>
            <li>
              <span > star_border </span>
            </li>
          </ul>
        </div>
        <h5 >${{ prod.price }}</h5>
        <div >
          <h4 >{{ prod.name }}</h4>
          <p >{{ prod.discription }}</p>
        </div>
      </div>
      <div >
        <a href="#" >
          <span > favorite_border </span>
          <span>Wishist</span>
        </a>
        <a href="#" >
          <span > shopping_cart </span>
          <span>View In Cart</span>
        </a>
      </div>
    </div>
  </div>
</div>

  • Related