Skip to content

Commit 7b7164c

Browse files
committed
fix(v-model): avoid duplicate model transforms
This happens when a component directly passes down its own data object to a child component. Fix #8436.
1 parent 69730fa commit 7b7164c

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed

Diff for: src/core/vdom/create-component.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,17 @@ function transformModel (options, data: any) {
252252
const event = (options.model && options.model.event) || 'input'
253253
;(data.props || (data.props = {}))[prop] = data.model.value
254254
const on = data.on || (data.on = {})
255-
if (isDef(on[event])) {
256-
on[event] = [data.model.callback].concat(on[event])
255+
const existing = on[event]
256+
const callback = data.model.callback
257+
if (isDef(existing)) {
258+
if (
259+
Array.isArray(existing)
260+
? existing.indexOf(callback) === -1
261+
: existing !== callback
262+
) {
263+
on[event] = [callback].concat(existing)
264+
}
257265
} else {
258-
on[event] = data.model.callback
266+
on[event] = callback
259267
}
260268
}

Diff for: test/unit/features/directives/model-component.spec.js

+56
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,60 @@ describe('Directive v-model component', () => {
148148
vm.$refs.input.$emit('input', ' foo o ')
149149
expect(vm.text).toBe('foo o')
150150
})
151+
152+
// #8436
153+
it('should not double transform mode props', () => {
154+
const BaseInput = {
155+
props: ['value'],
156+
render (h) {
157+
return h('input', {
158+
domProps: {
159+
value: this.value
160+
},
161+
on: {
162+
input: e => this.$emit('input', e.target.value)
163+
}
164+
})
165+
}
166+
}
167+
168+
const FunctionalWrapper = {
169+
functional: true,
170+
render (h, ctx) {
171+
return h(BaseInput, ctx.data)
172+
}
173+
}
174+
175+
let triggerCount = 0
176+
177+
const vm = new Vue({
178+
components: {
179+
FunctionalWrapper
180+
},
181+
template: `
182+
<div>
183+
<functional-wrapper v-model="val"/>
184+
</div>
185+
`,
186+
data: {
187+
internalVal: ''
188+
},
189+
computed: {
190+
val: {
191+
get () {
192+
return this.internalVal
193+
},
194+
set (val) {
195+
triggerCount++
196+
this.internalVal = val
197+
}
198+
}
199+
}
200+
}).$mount()
201+
202+
document.body.appendChild(vm.$el)
203+
triggerEvent(vm.$el.querySelector('input'), 'input')
204+
expect(triggerCount).toBe(1)
205+
document.body.removeChild(vm.$el)
206+
})
151207
})

0 commit comments

Comments
 (0)