Answer the question
In order to leave comments, you need to log in
How to filter by multiple values in VueJS?
The task is to filter the returned results by several values for the already obtained result and reset the filter itself with the button.
Filter:
<h6>{{ trans('calculator.filter') }}</h6>
<div class="row">
<div class="col">
<p>{{ trans('calculator.brand_filter') }}</p>
<select v-model="brand" class="custom-select">
<option v-for="brand in brands.sort()" :value="brand">{{ brand }}</option>
</select>
</div>
<div class="col">
<p>{{ trans('calculator.company_filter') }}</p>
<select v-model="company" class="custom-select">
<option v-for="company in companies.sort()" :value="company">{{ company }}</option>
</select></div>
<div class="col">
<p>{{ trans('calculator.country_filter') }}</p>
<select v-model="country" class="custom-select">
<option v-for="brand in countries.sort()" :value="brand">{{ brand }}</option>
</select></div>
<div class="col">
<p>{{ trans('calculator.side_filter') }}</p>
<select v-model="sidesFilter" class="custom-select">
<option v-for="side in sides.sort()" :value="side">{{ side }}</option>
</select></div>
<div class="col">
<p>{{ trans('calculator.rating_filter') }}</p>
<select v-model="ratingFilter" class="custom-select" disabled>
<option value="5" selected>5</option>
<option value="4">4</option>
<option value="3">3</option>
<option value="2">2</option>
<option value="1">1</option>
</select></div>
<a href="#">{{ trans('calculator.reset_filter') }}</a></div>
<div v-if="!profiles.length">
<h4>{{ trans('calculator.no_results') }}</h4>
</div>
<div v-for="profile in filteredProfiles" class="row feed">
<div class="col-3">
<img alt="" :src="`${profile.company.logo}`" width="100%">
</div>
<div class="col-5 no-padding">
<a :href="`/companies/${profile.company.id}`" target="_blank" class="title">{{profile.company.name}}</a>
<div>
<star-rating
v-model="profile.company.rating || 0"
read-only
:show-rating="false"
:star-size="16"
/>
<span>{{(profile.company.workingHours.isOpen) ? trans('calculator.open') : trans('calculator.closed') }} | </span>
<span>
{{roundTime(profile.company.workingHours.today.from)}}
-
{{roundTime(profile.company.workingHours.today.to)}}</span>
</div>
<span>{{ trans('calculator.brand') }}: {{profile.brand.name}}<br>{{ trans('calculator.country') }}: {{profile.brand.country}}</span>
<p class="text-muted">{{`${profile.sides}`}} {{ trans('calculator.profile_window') }}</p>
</div>
<div class="col-4">
<h5>{{ trans('calculator.price') }}: {{Math.round(profile.price)}} </h5>
<p>*{{ trans('calculator.pre_price') }} <i v-tooltip.top="trans('calculator.info_preprice')" class="fas fa-info-circle"></i></p>
<br>
<div class="responsive_results">
<button
class="button_calculator coolBeans"
@click="selectProfile(profile)"
data-toggle="modal"
data-target="#orderModal"
>
{{ trans('calculator.order') }}
</button></div>
</div>
</div>
export default {
props: ['profiles', 'onSend'],
data() {
return {
isModalOpen: false,
profile: {},
}
},
computed: {
filteredProfiles() {
return this.profiles.filter(
n => n.brand.name === this.brand,
n => n.company.name === this.company,
n => n.brand.country === this.country,
n => n.sides === this.side
},
brands() {
return [...new Set(this.profiles.map(n => n.brand.name))];
},
companies() {
return [...new Set(this.profiles.map(n => n.company.name))];
},
countries() {
return [...new Set(this.profiles.map(n => n.brand.country))];
},
sides() {
return [...new Set(this.profiles.map(n => n.sides))];
},
},
methods: {
roundTime(time) {
const timeStr = time.split(':');
timeStr.pop();
return timeStr.join(':');
},
selectProfile(profile) {
this.profile = profile;
},
orderProfile(profile) {
$('#orderModal').modal('hide');
this.onSend(profile);
}
}
}
<a href="#">{{ trans('calculator.reset_filter') }}</a>
Answer the question
In order to leave comments, you need to log in
It's all difficult. Four selects are very similar, four computed properties are very similar. Too much copypasta. We need to simplify.
First of all, we will carefully look at all these similar pieces of code, find where they differ, and based on these differences, we will make a description of the filters:
filters: [
{ name: 'calculator.brand_filter', getter: obj => obj.brand.name, value: '' },
{ name: 'calculator.company_filter', getter: obj => obj.company.name, value: '' },
{ name: 'calculator.country_filter', getter: obj => obj.brand.country, value: '' },
{ name: 'calculator.side_filter', getter: obj => obj.sides, value: '' },
],
computed: {
filteredProfiles() {
return this.filters.reduce((profiles, { value, getter }) => {
return value
? profiles.filter(n => getter(n) === value)
: profiles;
}, this.profiles);
},
},
Vue.component('filter-select', {
props: [ 'name', 'items', 'value' ],
template: `
<div>
<p>{{ name }}<p>
<select :value="value" @change="$emit('input', $event.target.value)">
<option value="">-</option>
<option v-for="n in items">{{ n }}</option>
</select>
</div>`
});
unique(arr, getter) {
return [...new Set(arr.map(getter))];
},
<filter-select
v-for="f in filters"
v-model="f.value"
:items="unique(profiles, f.getter)"
:name="trans(f.name)"
></filter-select>
resetFilters() {
this.filters.forEach(n => n.value = '');
},
<button @click="resetFilters">{{ trans('calculator.reset_filter') }}</button>
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question