Skip to content

Commit f2b0a8e

Browse files
committed
fix(v-model): avoid mutation when using Set models + fix multi select Set model update
1 parent 83a79a8 commit f2b0a8e

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

packages/runtime-dom/__tests__/directives/vModel.spec.ts

+3
Original file line numberDiff line numberDiff line change
@@ -884,18 +884,21 @@ describe('vModel', () => {
884884
foo.selected = true
885885
triggerEvent('change', input)
886886
await nextTick()
887+
expect(data.value).toBeInstanceOf(Set)
887888
expect(data.value).toMatchObject(new Set(['foo']))
888889

889890
foo.selected = false
890891
bar.selected = true
891892
triggerEvent('change', input)
892893
await nextTick()
894+
expect(data.value).toBeInstanceOf(Set)
893895
expect(data.value).toMatchObject(new Set(['bar']))
894896

895897
foo.selected = true
896898
bar.selected = true
897899
triggerEvent('change', input)
898900
await nextTick()
901+
expect(data.value).toBeInstanceOf(Set)
899902
expect(data.value).toMatchObject(new Set(['foo', 'bar']))
900903

901904
foo.selected = false

packages/runtime-dom/src/directives/vModel.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,13 @@ export const vModelCheckbox: ModelDirective<HTMLInputElement> = {
118118
assign(filtered)
119119
}
120120
} else if (isSet(modelValue)) {
121+
const cloned = new Set(modelValue)
121122
if (checked) {
122-
modelValue.add(elementValue)
123+
cloned.add(elementValue)
123124
} else {
124-
modelValue.delete(elementValue)
125+
cloned.delete(elementValue)
125126
}
127+
assign(cloned)
126128
} else {
127129
assign(getCheckboxValue(el, checked))
128130
}
@@ -168,15 +170,22 @@ export const vModelRadio: ModelDirective<HTMLInputElement> = {
168170
}
169171

170172
export const vModelSelect: ModelDirective<HTMLSelectElement> = {
171-
created(el, { modifiers: { number } }, vnode) {
173+
created(el, { value, modifiers: { number } }, vnode) {
174+
const isSetModel = isSet(value)
172175
addEventListener(el, 'change', () => {
173176
const selectedVal = Array.prototype.filter
174177
.call(el.options, (o: HTMLOptionElement) => o.selected)
175178
.map(
176179
(o: HTMLOptionElement) =>
177180
number ? toNumber(getValue(o)) : getValue(o)
178181
)
179-
el._assign(el.multiple ? selectedVal : selectedVal[0])
182+
el._assign(
183+
el.multiple
184+
? isSetModel
185+
? new Set(selectedVal)
186+
: selectedVal
187+
: selectedVal[0]
188+
)
180189
})
181190
el._assign = getModelAssigner(vnode)
182191
},

0 commit comments

Comments
 (0)