Browse Source

fix(v-model): use stricter check for <select> option update

close #6112
dev
Evan You 7 years ago
parent
commit
c70addf7d1
  1. 17
      src/platforms/web/runtime/directives/model.js
  2. 18
      test/unit/features/directives/model-select.spec.js

17
src/platforms/web/runtime/directives/model.js

@ -30,6 +30,7 @@ export default {
if (isIE || isEdge) {
setTimeout(cb, 0)
}
el._vOptions = [].map.call(el.options, getValue)
} else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
el._vModifiers = binding.modifiers
if (!binding.modifiers.lazy) {
@ -56,10 +57,9 @@ export default {
// 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 matching
// option in the DOM.
const needReset = el.multiple
? binding.value.some(v => hasNoMatchingOption(v, el.options))
: binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, el.options)
if (needReset) {
const prevOptions = el._vOptions
const curOptions = el._vOptions = [].map.call(el.options, getValue)
if (curOptions.some((o, i) => !looseEqual(o, prevOptions[i]))) {
trigger(el, 'change')
}
}
@ -101,15 +101,6 @@ function setSelected (el, binding, vm) {
}
}
function hasNoMatchingOption (value, options) {
for (let i = 0, l = options.length; i < l; i++) {
if (looseEqual(getValue(options[i]), value)) {
return false
}
}
return true
}
function getValue (option) {
return '_value' in option
? option._value

18
test/unit/features/directives/model-select.spec.js

@ -471,4 +471,22 @@ describe('Directive v-model select', () => {
expect(vm.$el.childNodes[0].selected).toBe(true)
}).then(done)
})
// #6112
it('should not set non-matching value to undefined if options did not change', done => {
const vm = new Vue({
data: {
test: '1'
},
template:
'<select v-model="test">' +
'<option>a</option>' +
'</select>'
}).$mount()
vm.test = '2'
waitForUpdate(() => {
expect(vm.test).toBe('2')
}).then(done)
})
})

Loading…
Cancel
Save