From: Evan You Date: Tue, 1 Dec 2020 16:40:14 +0000 (-0500) Subject: fix(v-model): avoid mutation when using Set models + fix multi select Set model update X-Git-Tag: v3.0.4~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f2b0a8e81d15eb8017c7fca5c1dff0e5f6a5573e;p=thirdparty%2Fvuejs%2Fcore.git fix(v-model): avoid mutation when using Set models + fix multi select Set model update --- diff --git a/packages/runtime-dom/__tests__/directives/vModel.spec.ts b/packages/runtime-dom/__tests__/directives/vModel.spec.ts index a1d729be48..8bd4b57978 100644 --- a/packages/runtime-dom/__tests__/directives/vModel.spec.ts +++ b/packages/runtime-dom/__tests__/directives/vModel.spec.ts @@ -884,18 +884,21 @@ describe('vModel', () => { foo.selected = true triggerEvent('change', input) await nextTick() + expect(data.value).toBeInstanceOf(Set) expect(data.value).toMatchObject(new Set(['foo'])) foo.selected = false bar.selected = true triggerEvent('change', input) await nextTick() + expect(data.value).toBeInstanceOf(Set) expect(data.value).toMatchObject(new Set(['bar'])) foo.selected = true bar.selected = true triggerEvent('change', input) await nextTick() + expect(data.value).toBeInstanceOf(Set) expect(data.value).toMatchObject(new Set(['foo', 'bar'])) foo.selected = false diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index 78a5b130f9..a157177f73 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -118,11 +118,13 @@ export const vModelCheckbox: ModelDirective = { assign(filtered) } } else if (isSet(modelValue)) { + const cloned = new Set(modelValue) if (checked) { - modelValue.add(elementValue) + cloned.add(elementValue) } else { - modelValue.delete(elementValue) + cloned.delete(elementValue) } + assign(cloned) } else { assign(getCheckboxValue(el, checked)) } @@ -168,7 +170,8 @@ export const vModelRadio: ModelDirective = { } export const vModelSelect: ModelDirective = { - created(el, { modifiers: { number } }, vnode) { + created(el, { value, modifiers: { number } }, vnode) { + const isSetModel = isSet(value) addEventListener(el, 'change', () => { const selectedVal = Array.prototype.filter .call(el.options, (o: HTMLOptionElement) => o.selected) @@ -176,7 +179,13 @@ export const vModelSelect: ModelDirective = { (o: HTMLOptionElement) => 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) },