diff --git a/src/platforms/web/runtime/directives/model.js b/src/platforms/web/runtime/directives/model.js index 89239816882..f707b036ad0 100644 --- a/src/platforms/web/runtime/directives/model.js +++ b/src/platforms/web/runtime/directives/model.js @@ -6,6 +6,8 @@ import { isTextInputType } from 'web/util/element' import { looseEqual, looseIndexOf } from 'shared/util' import { warn, isAndroid, isIE9, isIE, isEdge } from 'core/util/index' +import { mergeVNodeHook } from 'core/vdom/helpers/index' +import { emptyNode } from 'core/vdom/patch' /* istanbul ignore if */ if (isIE9) { @@ -18,10 +20,17 @@ if (isIE9) { }) } -export default { - inserted (el, binding, vnode) { +const directive = { + inserted (el, binding, vnode, oldVnode) { if (vnode.tag === 'select') { - setSelected(el, binding, vnode.context) + // #6903 + if (oldVnode !== emptyNode && !hasDirective(oldVnode, 'model')) { + mergeVNodeHook(vnode.data.hook || (vnode.data.hook = {}), 'postpatch', () => { + directive.componentUpdated(el, binding, vnode) + }) + } else { + setSelected(el, binding, vnode.context) + } el._vOptions = [].map.call(el.options, getValue) } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) { el._vModifiers = binding.modifiers @@ -136,3 +145,11 @@ function trigger (el, type) { e.initEvent(type, true, true) el.dispatchEvent(e) } + +function hasDirective (vnode, dirname) { + return vnode.data && + vnode.data.directives && + vnode.data.directives.some(dir => dir.name === dirname) +} + +export default directive diff --git a/test/unit/features/directives/model-select.spec.js b/test/unit/features/directives/model-select.spec.js index 7c265d25f79..c961224972b 100644 --- a/test/unit/features/directives/model-select.spec.js +++ b/test/unit/features/directives/model-select.spec.js @@ -546,4 +546,46 @@ describe('Directive v-model select', () => { expect(spy).not.toHaveBeenCalled() }).then(done) }) + + // #6903 + describe('should correctly handle v-model when the vnodes are the same', () => { + function makeInstance (foo) { + return new Vue({ + data: { + foo: foo, + options: ['b', 'c', 'd'], + value: 'c' + }, + template: + '
' + + '' + + '' + + '
' + }).$mount() + } + + it('register v-model', done => { + const vm = makeInstance(true) + + expect(vm.$el.firstChild.selectedIndex).toBe(0) + vm.foo = false + waitForUpdate(() => { + expect(vm.$el.firstChild.selectedIndex).toBe(1) + }).then(done) + }) + + it('remove v-model', done => { + const vm = makeInstance(false) + + expect(vm.$el.firstChild.selectedIndex).toBe(1) + vm.foo = true + waitForUpdate(() => { + expect(vm.$el.firstChild.selectedIndex).toBe(0) + }).then(done) + }) + }) })