Skip to content

Commit f8b9d81

Browse files
authored
Merge pull request #363 from xvaara/fix-select-with-object
Fix select/checkbox/radio with object
2 parents fce4ed8 + 9fc649d commit f8b9d81

15 files changed

+340
-563
lines changed

src/App.vue

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,29 @@
482482
<strong>{{ checkboxes.status }}</strong>
483483
</div>
484484
</div>
485+
<h4 class="m-2">array with uncheckedValue</h4>
486+
<div class="m-4">
487+
<b-form-checkbox
488+
id="checkbox-2"
489+
v-model="checkboxes.statusArray"
490+
name="checkbox-2"
491+
value="accepted"
492+
unchecked-value="not_accepted"
493+
>I accept the terms and use</b-form-checkbox
494+
>
495+
<b-form-checkbox
496+
id="checkbox-3"
497+
v-model="checkboxes.statusArray"
498+
name="checkbox-3"
499+
value="accepted2"
500+
unchecked-value="not_accepted2"
501+
>I accept the terms and use</b-form-checkbox
502+
>
503+
<div>
504+
State:
505+
<strong>{{ checkboxes.statusArray }}</strong>
506+
</div>
507+
</div>
485508
<h4 class="m-2">Individual</h4>
486509
<div class="row mx-4">
487510
<b-form-checkbox v-model="checkedDefault" class="col-4">Default</b-form-checkbox>
@@ -583,7 +606,8 @@
583606
<b-form-checkbox value="orange">Orange</b-form-checkbox>
584607
<b-form-checkbox value="apple">Apple</b-form-checkbox>
585608
<b-form-checkbox value="pineapple">Pineapple</b-form-checkbox>
586-
<b-form-checkbox value="grape">Grape</b-form-checkbox>
609+
<b-form-checkbox :value="{foo: 1}">Object</b-form-checkbox>
610+
<b-form-checkbox value="grape">Grapess</b-form-checkbox>
587611
</b-form-checkbox-group>
588612
<br />
589613
<div>
@@ -691,6 +715,7 @@
691715
<b-form-radio value="second">Or toggle this other custom radio</b-form-radio>
692716
<b-form-radio value="third" disabled>This one is Disabled</b-form-radio>
693717
<b-form-radio :value="{fourth: 4}">This is the 4th radio</b-form-radio>
718+
<b-form-radio :value="{fifth: 5}">This is the 5th radio</b-form-radio>
694719
</b-form-radio-group>
695720

696721
<div class="mt-3">
@@ -714,6 +739,10 @@
714739
</div>
715740
</div>
716741
<h4 class="m-2">Button styles radios</h4>
742+
<div class="mt-3">
743+
Selected:
744+
<strong>{{ radios.ex3.selected }}</strong>
745+
</div>
717746
<div class="m-4">
718747
<b-form-radio-group
719748
id="btn-radios-1"
@@ -1923,11 +1952,13 @@ export default defineComponent({
19231952
}
19241953
const checkboxes = reactive({
19251954
status: 'accepted',
1926-
selected: ['pineapple'],
1955+
statusArray: ['accepted'],
1956+
selected: ['pineapple', {foo: 1}],
19271957
options: [
19281958
{text: 'Orange', value: 'orange'},
19291959
{text: 'Apple', value: 'apple'},
19301960
{text: 'Pineapple', value: 'pineapple'},
1961+
{text: 'Object', value: {foo: 1}},
19311962
{html: '<b>Grape</b> (html content)', value: 'grape'},
19321963
],
19331964
})
@@ -1943,30 +1974,34 @@ export default defineComponent({
19431974
const radioSelected = ref()
19441975
const radios = reactive({
19451976
ex1: {
1946-
selected: 'first',
1977+
selected: {fifth: 5},
19471978
options: [
19481979
{text: 'Toggle this custom radio', value: 'first'},
19491980
{text: 'Or toggle this other custom radio', value: 'second'},
19501981
{text: 'This one is Disabled', value: 'third', disabled: true},
19511982
{text: 'This is the 4th radio', value: {fourth: 4}},
1983+
{text: 'This is the 5th radio', value: {fifth: 5}},
19521984
],
19531985
},
19541986
ex2: {
1955-
selected: 'A',
1987+
selected: {e: 1},
19561988
options: [
19571989
{item: 'A', name: 'Option A'},
19581990
{item: 'B', name: 'Option B'},
19591991
{item: 'D', name: 'Option C', notEnabled: true},
19601992
{item: {d: 1}, name: 'Option D'},
1993+
{item: {e: 1}, name: 'Option E'},
19611994
],
19621995
},
19631996
ex3: {
1964-
selected: 'radio1',
1997+
selected: {e: 1},
19651998
options: [
19661999
{text: 'Radio 1', value: 'radio1'},
19672000
{text: 'Radio 3', value: 'radio2'},
19682001
{text: 'Radio 3 (disabled)', value: 'radio3', disabled: true},
19692002
{text: 'Radio 4', value: 'radio4'},
2003+
{value: {d: 1}, text: 'Option D'},
2004+
{value: {e: 1}, text: 'Option E'},
19702005
],
19712006
},
19722007
})
@@ -1983,7 +2018,7 @@ export default defineComponent({
19832018
19842019
const formInputRangeValue = ref(3)
19852020
1986-
const formSelectSelected = ref()
2021+
const formSelectSelected = ref({foo: 'item 6', baz: false})
19872022
const formSelectMultipleSelected = ref<string[]>([])
19882023
formSelectMultipleSelected.value = ['first', 'second']
19892024
const formSelectOptions = [
@@ -1992,7 +2027,8 @@ export default defineComponent({
19922027
{text: 'Item 2', value: 'second'},
19932028
{html: '<b>Item</b> 3', value: 'third', disabled: true},
19942029
{text: 'Item 4'},
1995-
{text: 'Item 5', value: {foo: 'bar', baz: true}},
2030+
{text: 'Item 5', value: {foo: 'item 5', baz: true}},
2031+
{text: 'Item 6', value: {foo: 'item 6', baz: false}},
19962032
{
19972033
label: 'Grouped options',
19982034
options: [

src/components/BFormCheckbox/BFormCheckbox.vue

Lines changed: 35 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
:id="computedId"
55
v-bind="$attrs"
66
ref="input"
7+
v-model="localValue"
78
:class="inputClasses"
89
type="checkbox"
910
:disabled="disabled"
@@ -15,10 +16,8 @@
1516
:aria-required="name && required ? 'true' : null"
1617
:value="value"
1718
:indeterminate="indeterminate"
18-
:checked="isChecked"
19-
@click.stop="handleClick($event.target.checked)"
20-
@focus="focus()"
21-
@blur="blur()"
19+
@focus="isFocused = true"
20+
@blur="isFocused = false"
2221
/>
2322
<label
2423
v-if="$slots.default || !plain"
@@ -32,7 +31,7 @@
3231

3332
<script lang="ts">
3433
import {getClasses, getInputClasses, getLabelClasses} from '../../composables/useFormCheck'
35-
import {computed, defineComponent, onMounted, PropType, Ref, ref, watch} from 'vue'
34+
import {computed, defineComponent, onMounted, PropType, Ref, ref} from 'vue'
3635
import {InputSize} from '../../types'
3736
import useId from '../../composables/useId'
3837
@@ -66,12 +65,37 @@ export default defineComponent({
6665
const input: Ref<HTMLElement> = ref(null as unknown as HTMLElement)
6766
const isFocused = ref(false)
6867
69-
const localChecked = computed({
70-
get: () => props.modelValue,
68+
const localValue = computed({
69+
get: () => {
70+
if (props.uncheckedValue) {
71+
if (!Array.isArray(props.modelValue)) {
72+
return props.modelValue === props.value
73+
}
74+
return props.modelValue.indexOf(props.value) > -1
75+
}
76+
return props.modelValue
77+
},
7178
set: (newValue: any) => {
72-
emit('input', newValue)
73-
emit('update:modelValue', newValue)
74-
emit('change', newValue)
79+
let emitValue = newValue
80+
if (!Array.isArray(props.modelValue)) {
81+
emitValue = newValue ? props.value : props.uncheckedValue
82+
} else {
83+
if (props.uncheckedValue) {
84+
emitValue = props.modelValue
85+
if (newValue) {
86+
if (emitValue.indexOf(props.uncheckedValue) > -1)
87+
emitValue.splice(emitValue.indexOf(props.uncheckedValue), 1)
88+
emitValue.push(props.value)
89+
} else {
90+
if (emitValue.indexOf(props.value) > -1)
91+
emitValue.splice(emitValue.indexOf(props.value), 1)
92+
emitValue.push(props.uncheckedValue)
93+
}
94+
}
95+
}
96+
emit('input', emitValue)
97+
emit('update:modelValue', emitValue)
98+
emit('change', emitValue)
7599
},
76100
})
77101
@@ -86,45 +110,6 @@ export default defineComponent({
86110
const inputClasses = getInputClasses(props)
87111
const labelClasses = getLabelClasses(props)
88112
89-
watch(
90-
() => props.modelValue,
91-
(newValue) => {
92-
emit('input', newValue)
93-
}
94-
)
95-
96-
const focus = () => {
97-
isFocused.value = true
98-
if (!props.disabled) input.value.focus()
99-
}
100-
101-
const blur = () => {
102-
isFocused.value = false
103-
if (!props.disabled) {
104-
input.value.blur()
105-
}
106-
}
107-
108-
const handleClick = (checked: boolean) => {
109-
if (!Array.isArray(props.modelValue)) {
110-
localChecked.value = checked ? props.value : props.uncheckedValue
111-
} else {
112-
const tempArray = props.modelValue
113-
if (checked) {
114-
const index = tempArray.indexOf(props.value)
115-
if (index < 0) {
116-
tempArray.push(props.value)
117-
}
118-
} else {
119-
const index = tempArray.indexOf(props.value)
120-
if (index > -1) {
121-
tempArray.splice(index, 1)
122-
}
123-
}
124-
localChecked.value = tempArray
125-
}
126-
}
127-
128113
// TODO: make jest tests compatible with the v-focus directive
129114
if (props.autofocus) {
130115
onMounted(() => {
@@ -138,12 +123,9 @@ export default defineComponent({
138123
classes,
139124
inputClasses,
140125
labelClasses,
141-
localChecked,
126+
localValue,
142127
isChecked,
143128
isFocused,
144-
handleClick,
145-
focus,
146-
blur,
147129
}
148130
},
149131
})

src/components/BFormCheckbox/BFormCheckboxGroup.vue

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88
tabindex="-1"
99
>
1010
<template v-for="(item, key) in checkboxList" :key="key">
11-
<b-form-checkbox
12-
v-model="item.model"
13-
v-bind="item.props"
14-
@change="childUpdated($event, item.props?.value)"
15-
>
11+
<b-form-checkbox v-model="localValue" v-bind="item.props">
1612
<!-- eslint-disable vue/no-v-html -->
1713
<span v-if="item.html" v-html="item.html" />
1814
<!--eslint-enable-->
@@ -23,7 +19,7 @@
2319
</template>
2420

2521
<script lang="ts">
26-
import {computed, defineComponent, PropType, watch} from 'vue'
22+
import {computed, defineComponent, PropType} from 'vue'
2723
import {ColorVariant, Size} from '../../types'
2824
import useId from '../../composables/useId'
2925
import {
@@ -65,7 +61,7 @@ export default defineComponent({
6561
const computedId = useId(props.id, 'checkbox')
6662
const computedName = useId(props.name, 'checkbox')
6763
68-
const localChecked = computed({
64+
const localValue = computed({
6965
get: () => props.modelValue,
7066
set: (newValue: any) => {
7167
if (JSON.stringify(newValue) === JSON.stringify(props.modelValue)) return
@@ -82,42 +78,24 @@ export default defineComponent({
8278
.map((e, idx) => bindGroupProps(e, idx, props, computedName, computedId))
8379
.map((e) => ({
8480
...e,
85-
model: props.modelValue.find((mv) => e.props?.value === mv) ? e.props?.value : false,
8681
props: {
8782
switch: props.switches,
8883
...e.props,
8984
},
9085
}))
9186
)
9287
93-
const childUpdated = (newValue: any, checkedValue: any) => {
94-
const resp = props.modelValue.filter(
95-
(e) => JSON.stringify(e) !== JSON.stringify(checkedValue)
96-
)
97-
if (JSON.stringify(newValue) === JSON.stringify(checkedValue)) resp.push(newValue)
98-
emit('update:modelValue', resp)
99-
emit('change', resp)
100-
}
101-
10288
const attrs = getGroupAttr(props)
10389
const classes = getGroupClasses(props)
10490
105-
watch(
106-
() => props.modelValue,
107-
(newValue) => {
108-
emit('input', newValue)
109-
}
110-
)
111-
11291
// TODO: make jest tests compatible with the v-focus directive
11392
11493
return {
11594
attrs,
11695
classes,
11796
checkboxList,
118-
childUpdated,
11997
computedId,
120-
localChecked,
98+
localValue,
12199
}
122100
},
123101
})

0 commit comments

Comments
 (0)