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

This commit is contained in:
Evan You 2016-06-30 11:48:35 -04:00
parent 41a3b79ecd
commit 5b668a9222
2 changed files with 27 additions and 6 deletions

View File

@ -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]

View File

@ -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()
})
})