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()