]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(v-model): avoid mutation when using Set models + fix multi select Set model update
authorEvan You <yyx990803@gmail.com>
Tue, 1 Dec 2020 16:40:14 +0000 (11:40 -0500)
committerEvan You <yyx990803@gmail.com>
Tue, 1 Dec 2020 16:40:14 +0000 (11:40 -0500)
packages/runtime-dom/__tests__/directives/vModel.spec.ts
packages/runtime-dom/src/directives/vModel.ts

index a1d729be48c11705fbcf30a574378c95a3013444..8bd4b57978c20af9e42ba9b6901c5fab0bbb495d 100644 (file)
@@ -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
index 78a5b130f93063ae535b8b28578d1d5953dc4427..a157177f73c8bfddca2ac794f68e841f822aef96 100644 (file)
@@ -118,11 +118,13 @@ export const vModelCheckbox: ModelDirective<HTMLInputElement> = {
           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<HTMLInputElement> = {
 }
 
 export const vModelSelect: ModelDirective<HTMLSelectElement> = {
-  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<HTMLSelectElement> = {
           (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)
   },