#javascript #vue.js #vue-multiselect
Вопрос:
У меня есть компонент vue, в котором я в настоящее время успешно показываю результаты из объекта данных, а также успешно создал несколько полей множественного выбора. Моя проблема-фильтрация.
Я знаю, как я могу установить одно значение из множественного выбора и сравнить его (используя v-if), чтобы показать определенные результаты в HTML-div, но сейчас я совершенно не понимаю, как правильно выполнять фильтрацию на основе нескольких множественных выборов (тем более, что некоторые из них допускают несколько вариантов, которые хранят значения в массивах).
Я помещаю свой фрагмент ниже, но как я могу правильно сделать это, чтобы я мог фильтровать результаты на основе всех значений в соответствующих v-моделях для множественных выборов, при этом убедившись, что если выбраны «Все магазины» или «Все области», он допускает все значения для этого выбора?
— Другими словами, если пользователю не нравится выбор, и множественный выбор остается в заполнителе, все значения для этого выбора будут отображаться в DOM (сначала на основе других фильтров).
new Vue({
el: "#app",
components: {Multiselect: window.VueMultiselect.default},
data: {
selectedOutput: '',
selectedAreas:[],
selectedStores: [],
selectedCategories: [],
selectedShifts: [],
shifts: [
{id: 1, name: "First"},
{id: 2, name: "Second"}
],
categories: [
{id: 1, name: "electronics"},
{id: 1, name: "home"},
{id: 1, name: "auto"},
],
outputOptions: [
{id:1, name: "Sold"},
{id:2, name: "Purchased"}
],
areas: [
{value: 1, name: "East"},
{value: 1, name: "West"},
],
stores: [
{value: 1, name: "One"},
{value: 2, name: "Two"}
],
workNumbers: [
{
"Adam": {
"name": "Adam",
"title": "Manager",
"shift": "First",
"category": "electronics",
"area" : "East",
"store": "One",
"sold": 140,
"purchased": 15
},
"Ben": {
"name": "Ben",
"title": "Manager",
"shift": "First",
"category": "electronics",
"area" : "East",
"store": "One",
"sold": 225,
"purchased": 77
},
"Suzie": {
"name": "Suzie",
"title": "Manager",
"shift": "Second",
"category": "home",
"area" : "West",
"store": "Two",
"sold": 124,
"purchased": 55
},
"Reg": {
"name": "Reg",
"title": "Manager",
"shift": "Second",
"category": "home",
"area" : "West",
"store": "Two",
"sold": 66,
"purchased": 36
},
"Kelly": {
"name": "Kelly",
"title": "Manager",
"shift": "Second",
"category": "home",
"area" : "West",
"store": "Two",
"sold": 55,
"purchased": 2
},
}
]
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-multiselect/3.0.0-alpha.2/vue-multiselect.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/vue-multiselect/3.0.0-alpha.2/dist/vue-multiselect.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="uk-width-2-10" style="position: relative !important;">
<multiselect
v-model="selectedOutput"
:options="outputOptions"
:multiple="false"
:close-on-select="true"
label="name"
track-by="name"
@input="checkOutput"
></multiselect>
</div>
<div class="uk-width-2-10" style="position:relative;">
<multiselect
v-model="selectedShifts"
:options="shifts"
:multiple="true"
:close-on-select="true"
placeholder="All shifts"
label="name"
track-by="name"
></multiselect>
</div>
<div class="uk-width-2-10" style="position: relative !important;">
<multiselect
v-model="selectedCategories"
:options="categories"
:multiple="true"
:close-on-select="true"
placeholder="All categories"
label="name"
track-by="id"
></multiselect>
</div>
<div class="uk-width-2-10" style="position: relative !important;">
<multiselect
v-model="selectedAreas"
:options="areas"
:multiple="true"
:close-on-select="true"
placeholder="All areas"
label="name"
track-by="name"
></multiselect>
</div>
<div class="uk-width-2-10" style="position: relative !important;">
<multiselect
v-model="selectedstores"
:options="stores"
:multiple="true"
:close-on-select="true"
placeholder="All stores"
label="name"
track-by="value"
></multiselect>
</div>
<table>
<tbody v-if="selectedOutput.name === 'Sold'">
<tr v-for="(value, employee) in workNumbers" :key="employee">
<!-- this is where I need a condition to show based on filters, I believe-->
<td>{{name}} - {{sold}}</td>
</tr>
</tbody>
<tbody v-else-if="selectedOutput.name === 'Purchased'">
<tr v-for="(value, employee) in workNumbers" :key="employee">
<!-- this is where I need a condition to show based on filters, I believe-->
<td>{{name}} - {{purchased}}</td>
</tr>
</tbody>
</table>
</div>
Обновить:
Теперь я перешел к другой таблице, которая похожа, но она зацикливается вокруг разных объектов, чтобы создать другую модель, которая также передается через функцию для модального.
<tbody v-if="selectedOutput.name === 'Cubes'">
<tr v-for="(value, employee) in workNumbers" :key="employee">
<td v-for="date in dates" :key="date" >
<div v-for="(dateSpecificData, dateValue) in value.dates" :key="dateValue" @click="showModal(dateSpecificData)" :style="'background: ' (dateSpecificData.unavailable > 0 ? '#f7a7a3' : '#a8f0c6')">
<div v-if="dateValue == date ">
@{{dateSpecificData.sold}}
</div>
</div>
</td>
</tr>
</tbody>
Ответ №1:
Вы можете определить a computed-property
, который возвращает отфильтрованный список в соответствии с параметрами:
new Vue({
el: "#app",
components: { Multiselect: window.VueMultiselect.default },
data: () => ({
selectedOutput: '',
outputOptions: [ {id:1, name: "Sold"}, {id:2, name: "Purchased"} ],
selectedShifts: [],
shifts: [ {id: 1, name: "First"}, {id: 2, name: "Second"} ],
selectedCategories: [],
categories: [ {id: 1, name: "electronics"}, {id: 2, name: "home"}, {id: 3, name: "auto"} ],
selectedAreas:[],
areas: [ {value: 1, name: "East"}, {value: 1, name: "West"} ],
selectedStores: [],
stores: [ {value: 1, name: "One"}, {value: 2, name: "Two"} ],
workNumbers: [
{
"Adam": { "name": "Adam", "title": "Manager", "shift": "First", "category": "electronics", "area" : "East", "store": "One", "sold": 140, "purchased": 15 },
"Ben": { "name": "Ben", "title": "Manager", "shift": "First", "category": "home", "area" : "West", "store": "Two", "sold": 225, "purchased": 77 },
"Suzie": { "name": "Suzie", "title": "Manager", "shift": "Second", "category": "electronics", "area" : "East", "store": "One", "sold": 124, "purchased": 55 },
"Reg": { "name": "Reg", "title": "Manager", "shift": "Second", "category": "home", "area" : "West", "store": "Two", "sold": 66, "purchased": 36 },
"Kelly": { "name": "Kelly", "title": "Manager", "shift": "Second", "category": "auto", "area" : "West", "store": "Two", "sold": 55, "purchased": 2 }
}
]
}),
methods: {
filtedSelectedHelper(arr = [], val) {
return arr.length ? arr.some(({ name }) => name === val) : true;
}
},
computed: {
filteredWorkNumbers () {
const ouput = this.selectedOutput;
const filteredList =
this.workNumbers
.flatMap(Object.values)
.filter(({ shift, category, area, store }) =>
this.filtedSelectedHelper(this.selectedShifts, shift) amp;amp;
this.filtedSelectedHelper(this.selectedCategories, category) amp;amp;
this.filtedSelectedHelper(this.selectedAreas, area) amp;amp;
this.filtedSelectedHelper(this.selectedStores, store)
);
return !this.selectedOutput
? filteredList.map(({ name, sold, purchased }) =>
`${name} - ${sold} - ${purchased}`
)
: this.selectedOutput.name === "Sold"
? filteredList.map(({ name, sold }) =>
`${name} - ${sold}`
)
: filteredList.map(({ name, purchased }) =>
`${name} - ${purchased}`
)
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-multiselect@2.1.0"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-multiselect@2.1.0/dist/vue-multiselect.min.css">
<div id="app">
<div class="uk-width-2-10" style="position: relative !important;">
<multiselect
v-model="selectedOutput"
:options="outputOptions"
:multiple="false"
:close-on-select="true"
label="name"
track-by="name"
></multiselect>
</div>
<div class="uk-width-2-10" style="position:relative;">
<multiselect
v-model="selectedShifts"
:options="shifts"
:multiple="true"
:close-on-select="true"
placeholder="All shifts"
label="name"
track-by="name"
></multiselect>
</div>
<div class="uk-width-2-10" style="position: relative !important;">
<multiselect
v-model="selectedCategories"
:options="categories"
:multiple="true"
:close-on-select="true"
placeholder="All categories"
label="name"
track-by="id"
></multiselect>
</div>
<div class="uk-width-2-10" style="position: relative !important;">
<multiselect
v-model="selectedAreas"
:options="areas"
:multiple="true"
:close-on-select="true"
placeholder="All areas"
label="name"
track-by="name"
></multiselect>
</div>
<div class="uk-width-2-10" style="position: relative !important;">
<multiselect
v-model="selectedStores"
:options="stores"
:multiple="true"
:close-on-select="true"
placeholder="All stores"
label="name"
track-by="value"
></multiselect>
</div>
<table>
<tbody>
<tr v-for="str in filteredWorkNumbers" :key="str"><td>{{str}}</td></tr>
</tbody>
</table>
</div>
Ресурсы:
https://vuejs.org/v2/guide/computed.html
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Комментарии:
1. Спасибо вам за это, это действительно работает на этом столе, и ресурсы, которые вы приложили, помогают мне прояснить несколько вещей. Однако, если вы видите мое обновление, у меня есть аналогичная таблица в приложении, которая также создает другую модель, циклически обходя даты, а затем передает объект в вызове функции, чтобы я не мог применить тот же фильтр в этом случае (в вычисленном). Был бы способ выполнить фильтр специально для самого внутреннего замыкания, чтобы он отображал только допустимые записи, но при этом сохранял бы соглашение о том, как он зацикливается в html и переходит в вызов функции?
2. Я понимаю, что это отличается от моего первоначального вопроса, мне просто любопытно, есть ли альтернативный способ назвать его для этой аналогичной таблицы
3. @Geoff_S рад, что это помогло 🙂 Я не могу дать вам полный ответ, пока не увижу схемы данных, но я советую вам выполнить логику и вычисления в свойстве computed, чтобы оно возвращало массив, готовый для рендеринга. Не стесняйтесь ссылаться на демо-версию, если хотите, с дополнительными объяснениями.
4. @Majed_Badawi это то, что мне удалось собрать, это похожая таблица, но она циклически повторяется по-разному, так как структура данных также содержит даты, которые также циклически изменяются, и я хочу отправить весь объект в конце в функцию, которая будет отображать его в модальном режиме jsfiddle.net/h3dLbv1j
5. Может быть, можно скопировать весь цикл в моем HTML-коде в вычисляемую функцию, как вы сказали?