Kaynağa Gözat

warn non-Array value for <select multiple> (close #3191)

Evan You 9 yıl önce
ebeveyn
işleme
5b668a9222

+ 15 - 6
src/platforms/web/runtime/directives/model.js

@@ -32,7 +32,7 @@ export default {
       }
     }
     if (vnode.tag === 'select') {
-      setSelected(el, binding.value)
+      setSelected(el, binding, vnode.context)
     } else {
       if (!isAndroid) {
         el.addEventListener('compositionstart', onCompositionStart)
@@ -45,16 +45,15 @@ export default {
     }
   },
   componentUpdated (el, binding, vnode) {
-    const val = binding.value
     if (vnode.tag === 'select') {
-      setSelected(el, val)
+      setSelected(el, binding, vnode.context)
       // in case the options rendered by v-for have changed,
       // it's possible that the value is out-of-sync with the rendered options.
       // detect such cases and filter out values that no longer has a matchig
       // option in the DOM.
       const needReset = el.multiple
-        ? val.some(v => hasNoMatchingOption(v, el.options))
-        : hasNoMatchingOption(val, el.options)
+        ? binding.value.some(v => hasNoMatchingOption(v, el.options))
+        : hasNoMatchingOption(binding.value, el.options)
       if (needReset) {
         trigger(el, 'change')
       }
@@ -62,10 +61,20 @@ export default {
   }
 }
 
-function setSelected (el, value) {
+function setSelected (el, binding, vm) {
+  const value = binding.value
   const isMultiple = el.multiple
   if (!isMultiple) {
     el.selectedIndex = -1
+  } else if (!Array.isArray(value)) {
+    process.env.NODE_ENV !== 'production' && warn(
+      `<select multiple v-model="${binding.expression}"> ` +
+      `expects an Array value for its binding, but got ${
+        Object.prototype.toString.call(value).slice(8, -1)
+      }`,
+      vm
+    )
+    return
   }
   for (let i = 0, l = el.options.length; i < l; i++) {
     const option = el.options[i]

+ 12 - 0
test/unit/features/directives/model-select.spec.js

@@ -203,4 +203,16 @@ describe('Directive v-model select', () => {
     expect('inline selected attributes on <option> will be ignored when using v-model')
       .toHaveBeenWarned()
   })
+
+  it('should warn multiple with non-Array value', () => {
+    const vm = new Vue({
+      data: {
+        test: 'meh'
+      },
+      template:
+        '<select v-model="test" multiple></select>'
+    }).$mount()
+    expect('<select multiple v-model="test"> expects an Array value for its binding, but got String')
+      .toHaveBeenWarned()
+  })
 })