fix(v-model): mutate original array for v-model multi checkbox (#2663)
Note: this change will break non-deep `watch` on the `v-model` bound array since the array is no longer replaced. This can be considered part of the Array watch changes in v3 as detailed at https://v3.vuejs.org/guide/migration/watch.html This is unfortunate but unavoidable since the issue that it fixes is more important: `v-model` should definitely work with a non-ref reactive array. fix #2662
This commit is contained in:
parent
cd92836223
commit
87581cd266
@ -6,7 +6,8 @@ import {
|
|||||||
vModelDynamic,
|
vModelDynamic,
|
||||||
withDirectives,
|
withDirectives,
|
||||||
VNode,
|
VNode,
|
||||||
ref
|
ref,
|
||||||
|
reactive
|
||||||
} from '@vue/runtime-dom'
|
} from '@vue/runtime-dom'
|
||||||
|
|
||||||
const triggerEvent = (type: string, el: Element) => {
|
const triggerEvent = (type: string, el: Element) => {
|
||||||
@ -433,6 +434,78 @@ describe('vModel', () => {
|
|||||||
expect(bar.checked).toEqual(false)
|
expect(bar.checked).toEqual(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it(`should support the reactive array in setup as a checkbox model`, async () => {
|
||||||
|
const value = reactive<string[]>([])
|
||||||
|
|
||||||
|
const component = defineComponent({
|
||||||
|
setup() {
|
||||||
|
return () => {
|
||||||
|
return [
|
||||||
|
withVModel(
|
||||||
|
h('input', {
|
||||||
|
type: 'checkbox',
|
||||||
|
class: 'foo',
|
||||||
|
value: 'foo',
|
||||||
|
'onUpdate:modelValue': setValue.bind(this)
|
||||||
|
}),
|
||||||
|
value
|
||||||
|
),
|
||||||
|
withVModel(
|
||||||
|
h('input', {
|
||||||
|
type: 'checkbox',
|
||||||
|
class: 'bar',
|
||||||
|
value: 'bar',
|
||||||
|
'onUpdate:modelValue': setValue.bind(this)
|
||||||
|
}),
|
||||||
|
value
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
render(h(component), root)
|
||||||
|
|
||||||
|
const foo = root.querySelector('.foo')
|
||||||
|
const bar = root.querySelector('.bar')
|
||||||
|
|
||||||
|
foo.checked = true
|
||||||
|
triggerEvent('change', foo)
|
||||||
|
await nextTick()
|
||||||
|
expect(value).toMatchObject(['foo'])
|
||||||
|
|
||||||
|
bar.checked = true
|
||||||
|
triggerEvent('change', bar)
|
||||||
|
await nextTick()
|
||||||
|
expect(value).toMatchObject(['foo', 'bar'])
|
||||||
|
|
||||||
|
bar.checked = false
|
||||||
|
triggerEvent('change', bar)
|
||||||
|
await nextTick()
|
||||||
|
expect(value).toMatchObject(['foo'])
|
||||||
|
|
||||||
|
foo.checked = false
|
||||||
|
triggerEvent('change', foo)
|
||||||
|
await nextTick()
|
||||||
|
expect(value).toMatchObject([])
|
||||||
|
|
||||||
|
value.length = 0
|
||||||
|
value.push('foo')
|
||||||
|
await nextTick()
|
||||||
|
expect(bar.checked).toEqual(false)
|
||||||
|
expect(foo.checked).toEqual(true)
|
||||||
|
|
||||||
|
value.length = 0
|
||||||
|
value.push('bar')
|
||||||
|
await nextTick()
|
||||||
|
expect(foo.checked).toEqual(false)
|
||||||
|
expect(bar.checked).toEqual(true)
|
||||||
|
|
||||||
|
value.length = 0
|
||||||
|
await nextTick()
|
||||||
|
expect(foo.checked).toEqual(false)
|
||||||
|
expect(bar.checked).toEqual(false)
|
||||||
|
})
|
||||||
|
|
||||||
it(`should support Set as a checkbox model`, async () => {
|
it(`should support Set as a checkbox model`, async () => {
|
||||||
const component = defineComponent({
|
const component = defineComponent({
|
||||||
data() {
|
data() {
|
||||||
|
@ -111,11 +111,9 @@ export const vModelCheckbox: ModelDirective<HTMLInputElement> = {
|
|||||||
const index = looseIndexOf(modelValue, elementValue)
|
const index = looseIndexOf(modelValue, elementValue)
|
||||||
const found = index !== -1
|
const found = index !== -1
|
||||||
if (checked && !found) {
|
if (checked && !found) {
|
||||||
assign(modelValue.concat(elementValue))
|
modelValue.push(elementValue)
|
||||||
} else if (!checked && found) {
|
} else if (!checked && found) {
|
||||||
const filtered = [...modelValue]
|
modelValue.splice(index, 1)
|
||||||
filtered.splice(index, 1)
|
|
||||||
assign(filtered)
|
|
||||||
}
|
}
|
||||||
} else if (isSet(modelValue)) {
|
} else if (isSet(modelValue)) {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
|
Loading…
Reference in New Issue
Block a user