Skip to content

Commit 8a7b02a

Browse files
committed
avoid v-model with .trim/.number updating value when in focus (fix vuejs#4392)
1 parent b9376eb commit 8a7b02a

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

src/platforms/web/compiler/directives/model.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,12 @@ function genDefaultModel (
127127
valueExpression = number || type === 'number'
128128
? `_n(${valueExpression})`
129129
: valueExpression
130+
130131
let code = genAssignmentCode(value, valueExpression)
131132
if (isNative && needCompositionGuard) {
132133
code = `if($event.target.composing)return;${code}`
133134
}
135+
134136
// inputs with type="file" are read only and setting the input's
135137
// value will throw an error.
136138
if (process.env.NODE_ENV !== 'production' &&
@@ -140,8 +142,12 @@ function genDefaultModel (
140142
`File inputs are read only. Use a v-on:change listener instead.`
141143
)
142144
}
145+
143146
addProp(el, 'value', isNative ? `_s(${value})` : `(${value})`)
144147
addHandler(el, event, code, null, true)
148+
if (trim || number || type === 'number') {
149+
addHandler(el, 'blur', '$forceUpdate()')
150+
}
145151
}
146152

147153
function genSelect (

src/platforms/web/runtime/modules/dom-props.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function updateDOMProps (oldVnode: VNodeWithData, vnode: VNodeWithData) {
3535
elm._value = cur
3636
// avoid resetting cursor position when value is the same
3737
const strCur = cur == null ? '' : String(cur)
38-
if (elm.value !== strCur && !elm.composing) {
38+
if (elm.value !== strCur && !elm.composing && document.activeElement !== elm) {
3939
elm.value = strCur
4040
}
4141
} else {

test/unit/features/directives/model-text.spec.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,61 @@ describe('Directive v-model text', () => {
6464
expect(vm.test).toBe('what')
6565
})
6666

67+
it('.number focus and typing', (done) => {
68+
const vm = new Vue({
69+
data: {
70+
test: 0,
71+
update: 0
72+
},
73+
template:
74+
'<div>' +
75+
'<input ref="input" v-model="test" type="number">{{ update }}' +
76+
'<input ref="blur"/>' +
77+
'</div>'
78+
}).$mount()
79+
document.body.appendChild(vm.$el)
80+
vm.$refs.input.focus()
81+
expect(vm.test).toBe(0)
82+
vm.$refs.input.value = '1.0'
83+
triggerEvent(vm.$refs.input, 'input')
84+
expect(vm.test).toBe(1)
85+
vm.update++
86+
waitForUpdate(() => {
87+
expect(vm.$refs.input.value).toBe('1.0')
88+
vm.$refs.blur.focus()
89+
vm.update++
90+
}).then(() => {
91+
expect(vm.$refs.input.value).toBe('1')
92+
}).then(done)
93+
})
94+
95+
it('.trim focus and typing', (done) => {
96+
const vm = new Vue({
97+
data: {
98+
test: 'abc',
99+
update: 0
100+
},
101+
template:
102+
'<div>' +
103+
'<input ref="input" v-model.trim="test" type="text">{{ update }}' +
104+
'<input ref="blur"/>' +
105+
'</div>'
106+
}).$mount()
107+
document.body.appendChild(vm.$el)
108+
vm.$refs.input.focus()
109+
vm.$refs.input.value = ' abc '
110+
triggerEvent(vm.$refs.input, 'input')
111+
expect(vm.test).toBe('abc')
112+
vm.update++
113+
waitForUpdate(() => {
114+
expect(vm.$refs.input.value).toBe(' abc ')
115+
vm.$refs.blur.focus()
116+
vm.update++
117+
}).then(() => {
118+
expect(vm.$refs.input.value).toBe('abc')
119+
}).then(done)
120+
})
121+
67122
it('multiple inputs', (done) => {
68123
const spy = jasmine.createSpy()
69124
const vm = new Vue({

0 commit comments

Comments
 (0)