From 1e146037fa4280b502d0edf95936bc67e87fd339 Mon Sep 17 00:00:00 2001 From: Robert Pemberton Date: Thu, 16 Nov 2017 16:24:23 +0000 Subject: [PATCH] feat: warn if both v-model and v-bind:value used on same element (#7056) * test($compile): warn if v-model and :value used on same text input #7048 * test($compile): make v-model and v-bind:value warning apply to all but exceptions #7048 * test($compile): move v-model/:value conflict warner to model.js #7048 * style: split long warning messages onto new lines --- .../web/compiler/directives/model.js | 15 +++++++++++ .../features/directives/model-text.spec.js | 26 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/platforms/web/compiler/directives/model.js b/src/platforms/web/compiler/directives/model.js index 98d4259cf98..3ae0e75b27a 100644 --- a/src/platforms/web/compiler/directives/model.js +++ b/src/platforms/web/compiler/directives/model.js @@ -21,6 +21,7 @@ export default function model ( const modifiers = dir.modifiers const tag = el.tag const type = el.attrsMap.type + const attrsMap = el.attrsMap if (process.env.NODE_ENV !== 'production') { // inputs with type="file" are read only and setting the input's @@ -31,6 +32,20 @@ export default function model ( `File inputs are read only. Use a v-on:change listener instead.` ) } + + // warn if v-bind:value conflicts with v-model + if ( + (attrsMap['v-bind:value'] || attrsMap[':value']) && + type !== 'checkbox' && + type !== 'radio' && + tag !== 'select' + ) { + const vBindValue = attrsMap['v-bind:value'] ? 'v-bind:value' : ':value' + warn( + `${vBindValue} conflicts with v-model on the same element ` + + 'because the latter already expands to a value binding internally' + ) + } } if (el.component) { diff --git a/test/unit/features/directives/model-text.spec.js b/test/unit/features/directives/model-text.spec.js index 7e291356c2f..2c186cc16f4 100644 --- a/test/unit/features/directives/model-text.spec.js +++ b/test/unit/features/directives/model-text.spec.js @@ -250,6 +250,32 @@ describe('Directive v-model text', () => { expect('You are binding v-model directly to a v-for iteration alias').toHaveBeenWarned() }) + it('warn if v-model and v-bind:value conflict', () => { + new Vue({ + data: { + test: 'foo' + }, + template: '' + }).$mount() + expect( + 'v-bind:value conflicts with v-model on the same element because the latter already ' + + 'expands to a value binding internally' + ).toHaveBeenWarned() + }) + + it('warn if v-model and :value conflict', () => { + new Vue({ + data: { + test: 'foo' + }, + template: '' + }).$mount() + expect( + ':value conflicts with v-model on the same element because the latter already ' + + 'expands to a value binding internally' + ).toHaveBeenWarned() + }) + if (!isAndroid) { it('does not trigger extra input events with single compositionend', () => { const spy = jasmine.createSpy()