fix(v-model): avoid mutation when using Set models + fix multi select Set model update

This commit is contained in:
Evan You 2020-12-01 11:40:14 -05:00
parent 83a79a829c
commit f2b0a8e81d
2 changed files with 16 additions and 4 deletions

View File

@ -884,18 +884,21 @@ describe('vModel', () => {
foo.selected = true foo.selected = true
triggerEvent('change', input) triggerEvent('change', input)
await nextTick() await nextTick()
expect(data.value).toBeInstanceOf(Set)
expect(data.value).toMatchObject(new Set(['foo'])) expect(data.value).toMatchObject(new Set(['foo']))
foo.selected = false foo.selected = false
bar.selected = true bar.selected = true
triggerEvent('change', input) triggerEvent('change', input)
await nextTick() await nextTick()
expect(data.value).toBeInstanceOf(Set)
expect(data.value).toMatchObject(new Set(['bar'])) expect(data.value).toMatchObject(new Set(['bar']))
foo.selected = true foo.selected = true
bar.selected = true bar.selected = true
triggerEvent('change', input) triggerEvent('change', input)
await nextTick() await nextTick()
expect(data.value).toBeInstanceOf(Set)
expect(data.value).toMatchObject(new Set(['foo', 'bar'])) expect(data.value).toMatchObject(new Set(['foo', 'bar']))
foo.selected = false foo.selected = false

View File

@ -118,11 +118,13 @@ export const vModelCheckbox: ModelDirective<HTMLInputElement> = {
assign(filtered) assign(filtered)
} }
} else if (isSet(modelValue)) { } else if (isSet(modelValue)) {
const cloned = new Set(modelValue)
if (checked) { if (checked) {
modelValue.add(elementValue) cloned.add(elementValue)
} else { } else {
modelValue.delete(elementValue) cloned.delete(elementValue)
} }
assign(cloned)
} else { } else {
assign(getCheckboxValue(el, checked)) assign(getCheckboxValue(el, checked))
} }
@ -168,7 +170,8 @@ export const vModelRadio: ModelDirective<HTMLInputElement> = {
} }
export const vModelSelect: ModelDirective<HTMLSelectElement> = { export const vModelSelect: ModelDirective<HTMLSelectElement> = {
created(el, { modifiers: { number } }, vnode) { created(el, { value, modifiers: { number } }, vnode) {
const isSetModel = isSet(value)
addEventListener(el, 'change', () => { addEventListener(el, 'change', () => {
const selectedVal = Array.prototype.filter const selectedVal = Array.prototype.filter
.call(el.options, (o: HTMLOptionElement) => o.selected) .call(el.options, (o: HTMLOptionElement) => o.selected)
@ -176,7 +179,13 @@ export const vModelSelect: ModelDirective<HTMLSelectElement> = {
(o: HTMLOptionElement) => (o: HTMLOptionElement) =>
number ? toNumber(getValue(o)) : getValue(o) number ? toNumber(getValue(o)) : getValue(o)
) )
el._assign(el.multiple ? selectedVal : selectedVal[0]) el._assign(
el.multiple
? isSetModel
? new Set(selectedVal)
: selectedVal
: selectedVal[0]
)
}) })
el._assign = getModelAssigner(vnode) el._assign = getModelAssigner(vnode)
}, },