Skip to content
Advertisement

Search and filter features still doesn’t work properly (Vue JS)

I’m figuring out how my search and filter features can work properly. I created a search feature and filter from search results by stock, distance, price, and time response. My search feature is running well. However, the filter feature that I made still doesn’t work.

I want after I do a search, and want to filter the search further, there are options like stock and distance when one of the dropdowns changes, the search result item also changes based on the filter (for example: stock) is available or not. And there are also other filters such as price and time response. When I click on price, the items will be sorted according to the lowest price to the highest price. And when I click the time response, the search items will be in order from fast to late response.

Example Case

In Type, i choose BMW. And then i click search button. There will show 2 item results with type BMW. And then, in a filter Distance i choose 500 KM. It should, show only 1 result. But the filters not work.

And if there are 6 item result, and i click price the item will be sorted from the lowest price to the highest price

I have made the code like the one below, can anyone help me solve this problem?

new Vue({
  el: '#app',
  data: {
    selectedType: '',
    selectedCountry: '',
    selectedYear: '',
    selectedStock:'',
    selectedDistance:'',
    items: [{
        name: 'Carthy',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        stock: 'available',
        distance: '500',
        price: '1900',
        response: 'fast'
      },
            {
        name: 'Holand',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        stock: 'available',
        distance: '500',
        price: '1050',
        response: 'fast'
      },
      {
        name: 'Nolan',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        stock: 'available',
        distance: '500',
        price: '1000',
        response: 'fast'
      },
      {
        name: 'Edgar',
        type: 'bmw',
        year: '2020',
        country: 'belgium',
        stock: 'available',
        distance: '5000',
        price: '1200',
        response: 'fast'
      },
      {
        name: 'John',
        type: 'bmw',
        year: '2019',
        country: 'england',
        stock: 'available',
        distance: '500',
        price: '1500',
        response: 'fast'
      },
      {
        name: 'Axel',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        stock: 'sold',
        distance: '500',
        price: '1600',
        response: 'late'
      }
    ],
    searchResult: [],
    itemsToShow: 2,
    totalItems: 0,
    sortByPrice: true,
    sort: 'price',
    sortByTime: true,
    sort: 'time'
  },
  computed:{
    filterItem: function() {
      let filterStock = this.selectedStock,
        filterDistance = this.selectedDistance

      return this.searchResult.filter(function(item) {
        let filtered = true
        if (filterStock && filterStock.length > 0) {
          filtered = item.stock == filterStock
        }
        if (filtered) {
          if (filterDistance && filterDistance.length > 0) {
            filtered = item.distance == filterDistance
          }
        }
        return filtered
      })
    }
  },
  methods: {
    search: function() {
      let filterType = this.selectedType,
        filterCountry = this.selectedCountry,
        filterYear = this.selectedYear

      this.itemsToShow = 2;
      
      this.searchResult = this.items.filter(function(item) {
        let filtered = true
        if (filterType && filterType.length > 0) {
          filtered = item.type == filterType
        }
        if (filtered) {
          if (filterCountry && filterCountry.length > 0) {
            filtered = item.country == filterCountry
          }
        }
        if (filtered) {
          if (filterYear && filterYear.length > 0) {
            filtered = item.year == filterYear
          }
        }
        return filtered
      })
    },
    priceSort: function(){
        this.sortByPrice = !this.sortByPrice
      if(this.sortByPrice)
      this.sort = 'price'
    },
    timeSort: function(){
        this.sortByTime = !this.sortByTime
      if(this.sortByTime)
      this.sort = 'time'
    }
  },
  mounted() {
    this.search()
  }
})
.list-item{
  margin-top:50px;
}

#app{
  position:relative;
  padding-bottom: 200px;
}

span{
  margin: 0 15px;
  cursor:pointer;
}

.filter-box{
  margin-top:15px;
}

.card{
  box-shadow:0px 10px 16px rgba(0,0,0,0.16);
  width:400px;
  padding:20px 30px;
  margin-bottom:30px;
}

button{
  background-color: #1cf478;
  border:none;
  padding: 10px 25px;
  font-weight:bold;
  border-radius: 15px;
}

select{
  border:none;
  padding: 10px 15px;
  background-color:#c1c1c1; 
  border-radius:10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.1/vue.js"></script>

<div id="app">
  <div class="search-box">
    <select v-model="selectedType">
      <option value="" disabled selected hidden>Type</option>
      <option value="mercedes">Mercedes</option>
      <option value="bmw">BMW</option>
    </select>

    <select v-model="selectedCountry">
      <option value="" disabled selected hidden>Country</option>
      <option value="belgium">Belgium</option>
      <option value="england">England</option>
    </select>

    <select v-model="selectedYear">
      <option value="" disabled selected hidden>Year</option>
      <option value="2019">2019</option>
      <option value="2020">2020</option>
    </select>
    
    <button @click="search">Search</button>
  </div>
  
  <div class="filter-box">
    <h6>Filter:</h6>
    <select v-model="selectedStock" @change="filterItem">
      <option value="" disabled selected hidden>Stock</option>
      <option value="sold">Sold</option>
      <option value="available">Available</option>
    </select>
    
    <select v-model="selectedDistance" @change="filterItem">
      <option value="" disabled selected hidden>Kilometers</option>
      <option value="500">500 KM</option>
      <option value="5000">5000 KM</option>
      <option value="10000">10.000 KM</option>
    </select>
    
    <span class="price" @click="priceSort">Price</span>
    <span class="response" @click="timeSort">Time Response</span>
    
  </div>

  <section class="result">
    <div class="container-fluid">
        <div class="row list-item" v-for="(item, id) in searchResult" :key="id">
          <div class="col-3 card" v-if="id < itemsToShow">
            <p>Name: {{ item.name }}</p>
            <p>Car: {{ item.type }}</p>
            <p>Year: {{ item.year }}</p>
            <p>Country: {{ item.country }}</p>
            <p>Price: ${{ item.price }}</p>
            <p>stock: {{ item.stock }}</p>
            <p>distance: {{ item.distance }}</p>
          </div>
        </div>
      
        <div class="row">
          <div class="col-12">
            <button @click="itemsToShow += 1">Load More</button>
          </div>
        </div>
    </div>
  </section>
</div>

Advertisement

Answer

Please refer to this codesandbox for a working demo based on your code.

My changes

  1. Add filterResult in data on top of searchResult to handle filter results, and we only render filterResult as results. This would separate the logic of ‘search’ and ‘filter’, clearer for the logic.
  2. Whenever the filter selected value changes, we trigger filterItems methods as @click handler. (previously you’re using computed property and that’s not straightforward enough, we can simply call a method for @change and update the filter results data.
  3. Whenever the search is triggered, we reset the filter select values, and show all search results (filterResult would be the same as searchResult as there is no filter value).
  4. As for sort, for the two sort span elements, we could only update this.sort data, and use watch to trigger sortItems method whenever the sorting criteria change, it would be simpler. You may need to adapt sortItems method based on your needs. Of course, you can write two separate methods for these two ‘sort’ buttons, that’s totally up to you 🙂
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement