]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(v-model): should use dynamic directive on input with dynamic v-bind
authorEvan You <yyx990803@gmail.com>
Wed, 5 Feb 2020 20:21:47 +0000 (15:21 -0500)
committerEvan You <yyx990803@gmail.com>
Wed, 5 Feb 2020 20:21:47 +0000 (15:21 -0500)
packages/compiler-core/src/utils.ts
packages/compiler-dom/__tests__/transforms/__snapshots__/vModel.spec.ts.snap
packages/compiler-dom/__tests__/transforms/vModel.spec.ts
packages/compiler-dom/src/transforms/vModel.ts
packages/compiler-ssr/src/transforms/ssrTransformElement.ts
packages/compiler-ssr/src/transforms/ssrVModel.ts

index 78e952e43ede85b312cbfb223d417745e5030293..d160e96ee959f0d9c96f76bb0cb986b6bd4c8724 100644 (file)
@@ -205,6 +205,17 @@ export function findProp(
   }
 }
 
+export function hasDynamicKeyVBind(node: ElementNode): boolean {
+  return node.props.some(
+    p =>
+      p.type === NodeTypes.DIRECTIVE &&
+      p.name === 'bind' &&
+      (!p.arg || // v-bind="obj"
+      p.arg.type !== NodeTypes.SIMPLE_EXPRESSION || // v-bind:[_ctx.foo]
+        !p.arg.isStatic) // v-bind:[foo]
+  )
+}
+
 export function createBlockExpression(
   blockExp: BlockCodegenNode,
   context: TransformContext
index f996e95578716aa41368c092c71008e7f0fcc2c2..88bba3b05953637dc0615f8f96e77a78ab213ee8 100644 (file)
@@ -1,5 +1,42 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`compiler: transform v-model input w/ dynamic v-bind 1`] = `
+"const _Vue = Vue
+
+return function render() {
+  with (this) {
+    const { vModelDynamic: _vModelDynamic, mergeProps: _mergeProps, createVNode: _createVNode, withDirectives: _withDirectives, createBlock: _createBlock, openBlock: _openBlock } = _Vue
+    
+    return (_openBlock(), _withDirectives(_createBlock(\\"input\\", _mergeProps(obj, {
+      modelValue: model,
+      \\"onUpdate:modelValue\\": $event => (model = $event)
+    }), null, 16 /* FULL_PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]), [
+      [_vModelDynamic, model]
+    ]))
+  }
+}"
+`;
+
+exports[`compiler: transform v-model input w/ dynamic v-bind 2`] = `
+"const _Vue = Vue
+
+return function render() {
+  with (this) {
+    const { vModelDynamic: _vModelDynamic, createVNode: _createVNode, withDirectives: _withDirectives, resolveDirective: _resolveDirective, createBlock: _createBlock, openBlock: _openBlock } = _Vue
+    
+    const _directive_bind = _resolveDirective(\\"bind\\")
+    
+    return (_openBlock(), _withDirectives(_createBlock(\\"input\\", {
+      modelValue: model,
+      \\"onUpdate:modelValue\\": $event => (model = $event)
+    }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]), [
+      [_directive_bind, val, key],
+      [_vModelDynamic, model]
+    ]))
+  }
+}"
+`;
+
 exports[`compiler: transform v-model modifiers .lazy 1`] = `
 "const _Vue = Vue
 
index a70e117adf019d874ded23fcba848b1e2c77fc89..acf9cb95b11660764c969bdaa294d45bd40dfd51 100644 (file)
@@ -63,6 +63,19 @@ describe('compiler: transform v-model', () => {
     expect(generate(root).code).toMatchSnapshot()
   })
 
+  test('input w/ dynamic v-bind', () => {
+    const root = transformWithModel('<input v-bind="obj" v-model="model" />')
+
+    expect(root.helpers).toContain(V_MODEL_DYNAMIC)
+    expect(generate(root).code).toMatchSnapshot()
+
+    const root2 = transformWithModel(
+      '<input v-bind:[key]="val" v-model="model" />'
+    )
+    expect(root2.helpers).toContain(V_MODEL_DYNAMIC)
+    expect(generate(root2).code).toMatchSnapshot()
+  })
+
   test('simple expression for select', () => {
     const root = transformWithModel('<select v-model="model" />')
 
index 83d623f50772b918c14417391fa36310f5da9885..e82ad780f19fec846144faa2ea60a1ee3fb7c71a 100644 (file)
@@ -3,7 +3,8 @@ import {
   DirectiveTransform,
   ElementTypes,
   findProp,
-  NodeTypes
+  NodeTypes,
+  hasDynamicKeyVBind
 } from '@vue/compiler-core'
 import { createDOMCompilerError, DOMErrorCodes } from '../errors'
 import {
@@ -75,6 +76,10 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
               break
           }
         }
+      } else if (hasDynamicKeyVBind(node)) {
+        // element has bindings with dynamic keys, which can possibly contain
+        // "type".
+        directiveToUse = V_MODEL_DYNAMIC
       } else {
         // text type
         __DEV__ && checkDuplicatedValue()
index 4f76441089c8bbe89e80538050c29e1115abc312..feacbd893c405363436a914a6cd265888d13420e 100644 (file)
@@ -19,7 +19,8 @@ import {
   JSChildNode,
   ArrayExpression,
   createAssignmentExpression,
-  TextNode
+  TextNode,
+  hasDynamicKeyVBind
 } from '@vue/compiler-dom'
 import { escapeHtml, isBooleanAttr, isSSRSafeAttrName } from '@vue/shared'
 import { createSSRCompilerError, SSRErrorCodes } from '../errors'
@@ -46,14 +47,7 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
       // v-bind="obj" or v-bind:[key] can potentially overwrite other static
       // attrs and can affect final rendering result, so when they are present
       // we need to bail out to full `renderAttrs`
-      const hasDynamicVBind = node.props.some(
-        p =>
-          p.type === NodeTypes.DIRECTIVE &&
-          p.name === 'bind' &&
-          (!p.arg || // v-bind="obj"
-          p.arg.type !== NodeTypes.SIMPLE_EXPRESSION || // v-bind:[_ctx.foo]
-            !p.arg.isStatic) // v-bind:[foo]
-      )
+      const hasDynamicVBind = hasDynamicKeyVBind(node)
       if (hasDynamicVBind) {
         const { props } = buildProps(node, context, node.props, true /* ssr */)
         if (props) {
index 8d4c0ad6dfb8fd1c62ef3ed4f5e78929d73e4db4..61933fe9b52bc46f0fcdb96048928c896f80cc26 100644 (file)
@@ -96,7 +96,8 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
       checkDuplicatedValue()
       node.children = [createInterpolation(model, model.loc)]
     } else if (node.tag === 'select') {
-      // TODO
+      // NOOP
+      // select relies on client-side directive to set initial selected state.
     } else {
       context.onError(
         createDOMCompilerError(