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>
Please refer to this codesandbox for a working demo based on your code.
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.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.filterResult
would be the same as searchResult
as there is no filter value).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 :)