Skip to content

Commit c70addf

Browse files
committed
fix(v-model): use stricter check for <select> option update
close #6112
1 parent be3dc9c commit c70addf

File tree

2 files changed

+22
-13
lines changed

2 files changed

+22
-13
lines changed

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

+4-13
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default {
3030
if (isIE || isEdge) {
3131
setTimeout(cb, 0)
3232
}
33+
el._vOptions = [].map.call(el.options, getValue)
3334
} else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
3435
el._vModifiers = binding.modifiers
3536
if (!binding.modifiers.lazy) {
@@ -56,10 +57,9 @@ export default {
5657
// it's possible that the value is out-of-sync with the rendered options.
5758
// detect such cases and filter out values that no longer has a matching
5859
// option in the DOM.
59-
const needReset = el.multiple
60-
? binding.value.some(v => hasNoMatchingOption(v, el.options))
61-
: binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, el.options)
62-
if (needReset) {
60+
const prevOptions = el._vOptions
61+
const curOptions = el._vOptions = [].map.call(el.options, getValue)
62+
if (curOptions.some((o, i) => !looseEqual(o, prevOptions[i]))) {
6363
trigger(el, 'change')
6464
}
6565
}
@@ -101,15 +101,6 @@ function setSelected (el, binding, vm) {
101101
}
102102
}
103103

104-
function hasNoMatchingOption (value, options) {
105-
for (let i = 0, l = options.length; i < l; i++) {
106-
if (looseEqual(getValue(options[i]), value)) {
107-
return false
108-
}
109-
}
110-
return true
111-
}
112-
113104
function getValue (option) {
114105
return '_value' in option
115106
? option._value

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

+18
Original file line numberDiff line numberDiff line change
@@ -471,4 +471,22 @@ describe('Directive v-model select', () => {
471471
expect(vm.$el.childNodes[0].selected).toBe(true)
472472
}).then(done)
473473
})
474+
475+
// #6112
476+
it('should not set non-matching value to undefined if options did not change', done => {
477+
const vm = new Vue({
478+
data: {
479+
test: '1'
480+
},
481+
template:
482+
'<select v-model="test">' +
483+
'<option>a</option>' +
484+
'</select>'
485+
}).$mount()
486+
487+
vm.test = '2'
488+
waitForUpdate(() => {
489+
expect(vm.test).toBe('2')
490+
}).then(done)
491+
})
474492
})

0 commit comments

Comments
 (0)