Skip to content

Commit 9e9aa80

Browse files
authored
Merge pull request #15 from kevinkosterr/5-multiselect
Add multiselect to `FieldSelect`
2 parents 81fdacf + 2fec646 commit 9e9aa80

File tree

2 files changed

+68
-6
lines changed

2 files changed

+68
-6
lines changed

__tests__/components/fields/FieldSelect.spec.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe('Test FieldSelect', () => {
5151

5252
it('Should update model value', async () => {
5353
config.global.components = { FieldSelect }
54-
const formWrapper = mountFormGenerator(form.schema, props)
54+
const formWrapper = mountFormGenerator(form.schema, form.model)
5555
const selectComp = formWrapper.findComponent(FieldSelect)
5656
expect(selectComp.exists()).toBeTruthy()
5757

@@ -63,4 +63,27 @@ describe('Test FieldSelect', () => {
6363
expect(selectComp.vm.isOpened).toBeFalsy()
6464
})
6565

66+
it('Should update model value, with multiple option', async () => {
67+
config.global.components = { FieldSelect }
68+
const schema = { fields: [
69+
{ ...form.schema.fields[0], multiple: true }
70+
] }
71+
const model = { selectModel: [] }
72+
const formWrapper = mountFormGenerator(schema, model)
73+
74+
expect(formWrapper.vm.model.selectModel.length).toBe(0)
75+
const fieldSelect = formWrapper.findComponent(FieldSelect)
76+
expect(fieldSelect.exists()).toBeTruthy()
77+
78+
await fieldSelect.find('.vfg-select-label').trigger('click')
79+
await fieldSelect.vm.$nextTick()
80+
await fieldSelect.find('.vfg-select-option').trigger('click')
81+
expect(formWrapper.vm.model.selectModel.length).toBe(1)
82+
83+
await fieldSelect.find('.vfg-select-label').trigger('click')
84+
await fieldSelect.vm.$nextTick()
85+
await fieldSelect.findAll('.vfg-select-option')[2].trigger('click')
86+
expect(formWrapper.vm.model.selectModel.length).toBe(2)
87+
})
88+
6689
})

src/fields/input/FieldSelect.vue

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
<template>
22
<div class="vfg-select">
33
<span v-on-click-outside="() => isOpened = false" class="vfg-select-label" :class="{'text-muted': !selectedName}" @click.prevent="onClickInput">
4-
<template v-if="selectedName">{{ selectedName }}</template>
4+
<template v-if="selectedNames.length">
5+
<span v-for="(selectedName, index) in selectedNames" :key="selectedName">
6+
<template v-if="index !== 0">, </template>{{ selectedName }}
7+
</span>
8+
</template>
59
<template v-else>{{ field.placeholder || 'Select an option' }}</template>
610
<span style="float:right;">
711
<!-- ChevronDown from https://heroicons.com -->
@@ -20,10 +24,21 @@
2024
v-for="option in field.options"
2125
:key="option.value"
2226
class="vfg-select-option"
23-
:class="{'selected': currentModelValue === option.value}"
27+
:class="{'selected': isSelected(option)}"
2428
@click.prevent="selectOption(option)"
2529
>
2630
{{ option.name }}
31+
<span v-if="isSelected(option)" style="float: right;">
32+
<!-- X-Mark Icon from https://heroicons.com -->
33+
<svg
34+
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
35+
stroke-width="1.5"
36+
stroke="currentColor" style="height: 15px;"
37+
>
38+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
39+
</svg>
40+
41+
</span>
2742
</div>
2843
</div>
2944
</div>
@@ -44,8 +59,14 @@ export default {
4459
}
4560
},
4661
computed: {
47-
selectedName () {
48-
return this.currentModelValue ? this.field.options.find(o => o.value === this.currentModelValue).name : undefined
62+
selectedNames () {
63+
if (!this.currentModelValue) return []
64+
65+
if (Array.isArray(this.currentModelValue) && this.field.multiple) {
66+
return this.field.options.filter(o => this.currentModelValue.includes(o.value)).map(o => o.name)
67+
} else {
68+
return [ this.field.options.find(o => o.value === this.currentModelValue).name ]
69+
}
4970
}
5071
},
5172
methods: {
@@ -56,8 +77,26 @@ export default {
5677
}
5778
this.isOpened = true
5879
},
80+
isSelected (option) {
81+
return this.currentModelValue?.includes(option.value) ?? false
82+
},
5983
selectOption (option) {
60-
this.$emit('onInput', option.value)
84+
if (!this.field.multiple) {
85+
const isSelected = this.currentModelValue === option.value
86+
this.$emit('onInput', isSelected ? '' : option.value)
87+
} else {
88+
let selectedValues = [ ...this.currentModelValue ]
89+
const isSelected = selectedValues.includes(option.value)
90+
91+
if (isSelected) {
92+
selectedValues = selectedValues.filter(o => o !== option.value)
93+
} else {
94+
selectedValues.push(option.value)
95+
}
96+
97+
98+
this.$emit('onInput', selectedValues)
99+
}
61100
this.isOpened = false
62101
}
63102
}

0 commit comments

Comments
 (0)