From eb848a6f1db0bd87bcf57d8706392ddf8676b189 Mon Sep 17 00:00:00 2001 From: Chris Casola Date: Mon, 2 Oct 2017 21:26:48 -0400 Subject: [PATCH] feat(v-model): warn when v-model is bound on non-existant key Warn when v-model is bound to a non-existant key since that key will not be reactive. Fixes #5932 --- src/compiler/codegen/index.js | 15 +++++++++++++++ src/platforms/web/runtime/directives/model.js | 4 ++++ test/unit/features/directives/model-text.spec.js | 14 ++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/compiler/codegen/index.js b/src/compiler/codegen/index.js index 46c54867bbb..d40813a53e9 100644 --- a/src/compiler/codegen/index.js +++ b/src/compiler/codegen/index.js @@ -291,6 +291,7 @@ function genDirectives (el: ASTElement, state: CodegenState): string | void { needRuntime = !!gen(el, dir, state.warn) } if (needRuntime) { + let warning hasRuntime = true res += `{name:"${dir.name}",rawName:"${dir.rawName}"${ dir.value ? `,value:(${dir.value}),expression:${JSON.stringify(dir.value)}` : '' @@ -298,6 +299,8 @@ function genDirectives (el: ASTElement, state: CodegenState): string | void { dir.arg ? `,arg:"${dir.arg}"` : '' }${ dir.modifiers ? `,modifiers:${JSON.stringify(dir.modifiers)}` : '' + }${ + process.env.NODE_ENV !== 'production' && (warning = genValidateValue(dir.value)) ? `,warn:${warning}` : '' }},` } } @@ -490,3 +493,15 @@ function transformSpecialNewlines (text: string): string { .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029') } + +function genValidateValue (expr: string): string { + const parts = expr.split('.') + if (parts.length > 1) { + const parent = parts.slice(0, -1).join('.') + const last = parts[parts.length - 1] + if (last.indexOf('[') < 0) { + return `!('${last}' in ${parent}) ? 'You are binding v-model to a key that does not exist, expression: ${expr}' : ''` + } + } + return '' +} diff --git a/src/platforms/web/runtime/directives/model.js b/src/platforms/web/runtime/directives/model.js index 89239816882..0591a21e142 100644 --- a/src/platforms/web/runtime/directives/model.js +++ b/src/platforms/web/runtime/directives/model.js @@ -41,6 +41,10 @@ export default { } } } + + if (process.env.NODE_ENV !== 'production' && 'warn' in binding) { + warn(binding.warn) + } }, componentUpdated (el, binding, vnode) { if (vnode.tag === 'select') { diff --git a/test/unit/features/directives/model-text.spec.js b/test/unit/features/directives/model-text.spec.js index 7032574ff56..8c951038d87 100644 --- a/test/unit/features/directives/model-text.spec.js +++ b/test/unit/features/directives/model-text.spec.js @@ -354,5 +354,19 @@ describe('Directive v-model text', () => { done() }, 16) }) + + it('warn binding v-model to non-existant data property', () => { + new Vue({ + data: { + testData: {} + }, + template: ` +
+ +
+ ` + }).$mount() + expect('You are binding v-model to a key that does not exist, expression: testData.missingKey').toHaveBeenWarned() + }) } })