From 7f542a9593f9858a5dd3d347ac9e4ef2411088dd Mon Sep 17 00:00:00 2001 From: jkzing Date: Sun, 23 Jul 2017 22:19:54 +0800 Subject: [PATCH 1/3] feat: add failing test for #6193 --- .../features/directives/model-select.spec.js | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/unit/features/directives/model-select.spec.js b/test/unit/features/directives/model-select.spec.js index 2f7e20eac2c..8c2a259ef5d 100644 --- a/test/unit/features/directives/model-select.spec.js +++ b/test/unit/features/directives/model-select.spec.js @@ -517,4 +517,33 @@ describe('Directive v-model select', () => { expect(vm.test).toBe('2') }).then(done) }) + + // #6193 + it('should not trigger change event when match option can be found for each value', done => { + const spy = jasmine.createSpy() + const vm = new Vue({ + data: { + options: ['1'] + }, + computed: { + test: { + get () { + return '1' + }, + set () { + spy() + } + } + }, + template: + '' + }).$mount() + + vm.options = ['1', '2'] + waitForUpdate(() => { + expect(spy).not.toHaveBeenCalled() + }).then(done) + }) }) From 22e8952dc0d5318007b9d9c8653654f5f58b406a Mon Sep 17 00:00:00 2001 From: jkzing Date: Sun, 23 Jul 2017 22:21:54 +0800 Subject: [PATCH 2/3] fix(v-model): add non-matching check back change event should not be triggered if still can found matching option for each value --- src/platforms/web/runtime/directives/model.js | 18 +++++++++++++++++- .../features/directives/model-select.spec.js | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/platforms/web/runtime/directives/model.js b/src/platforms/web/runtime/directives/model.js index ee355978421..fda7b45179c 100644 --- a/src/platforms/web/runtime/directives/model.js +++ b/src/platforms/web/runtime/directives/model.js @@ -60,7 +60,14 @@ export default { 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') + // trigger change event if + // no matching option found for at least one value + const needReset = el.multiple + ? binding.value.some(v => hasNoMatchingOption(v, el.options)) + : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, el.options) + if (needReset) { + trigger(el, 'change') + } } } } @@ -101,6 +108,15 @@ 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 diff --git a/test/unit/features/directives/model-select.spec.js b/test/unit/features/directives/model-select.spec.js index 8c2a259ef5d..629e5a2f440 100644 --- a/test/unit/features/directives/model-select.spec.js +++ b/test/unit/features/directives/model-select.spec.js @@ -519,7 +519,7 @@ describe('Directive v-model select', () => { }) // #6193 - it('should not trigger change event when match option can be found for each value', done => { + it('should not trigger change event when matching option can be found for each value', done => { const spy = jasmine.createSpy() const vm = new Vue({ data: { From 44840f1e405e0076c6c27fcfe13938a67b41d892 Mon Sep 17 00:00:00 2001 From: jkzing Date: Mon, 24 Jul 2017 23:53:52 +0800 Subject: [PATCH 3/3] feat: refactor hasNoMatchingOption with [].every --- src/platforms/web/runtime/directives/model.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/platforms/web/runtime/directives/model.js b/src/platforms/web/runtime/directives/model.js index fda7b45179c..72da9f45fe2 100644 --- a/src/platforms/web/runtime/directives/model.js +++ b/src/platforms/web/runtime/directives/model.js @@ -63,8 +63,8 @@ export default { // trigger change event if // no matching option found for at least one value const needReset = el.multiple - ? binding.value.some(v => hasNoMatchingOption(v, el.options)) - : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, el.options) + ? binding.value.some(v => hasNoMatchingOption(v, curOptions)) + : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions) if (needReset) { trigger(el, 'change') } @@ -109,12 +109,7 @@ 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 + return options.every(o => !looseEqual(o, value)) } function getValue (option) {