Skip to content

Commit 111ca65

Browse files
fix(b-form-input): fix debounce when value does not change (#5632)
* fix(b-form-input, b-form-textarea): fix debounce when value does not change * Update form-text.js * Update form-text.js Co-authored-by: Jacob Müller <jacob.mueller.elz@gmail.com>
1 parent f10103e commit 111ca65

File tree

2 files changed

+57
-26
lines changed

2 files changed

+57
-26
lines changed

src/components/form-input/form-input.spec.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,33 @@ describe('form-input', () => {
871871
// `input` event should not have emitted new event
872872
expect(wrapper.emitted('input').length).toBe(4)
873873

874+
$input.element.value = 'abc'
875+
await $input.trigger('input')
876+
expect($input.element.value).toBe('abc')
877+
// `v-model` update event should not have emitted new event
878+
expect(wrapper.emitted('update').length).toBe(2)
879+
// `input` event should be emitted
880+
expect(wrapper.emitted('input').length).toBe(5)
881+
expect(wrapper.emitted('input')[4][0]).toBe('abc')
882+
883+
$input.element.value = 'abcd'
884+
await $input.trigger('input')
885+
expect($input.element.value).toBe('abcd')
886+
// `v-model` update event should not have emitted new event
887+
expect(wrapper.emitted('update').length).toBe(2)
888+
// `input` event should be emitted
889+
expect(wrapper.emitted('input').length).toBe(6)
890+
expect(wrapper.emitted('input')[5][0]).toBe('abcd')
891+
892+
// Advance timer
893+
jest.runOnlyPendingTimers()
894+
// Should update the v-model
895+
expect($input.element.value).toBe('abcd')
896+
// `v-model` update event should not have emitted new event
897+
expect(wrapper.emitted('update').length).toBe(2)
898+
// `input` event should not have emitted new event
899+
expect(wrapper.emitted('input').length).toBe(6)
900+
874901
wrapper.destroy()
875902
})
876903

src/mixins/form-text.js

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -161,35 +161,39 @@ export default {
161161
if (lazy && !force) {
162162
return
163163
}
164-
value = this.modifyValue(value)
165-
if (value !== this.vModelValue) {
166-
this.clearDebounce()
167-
const doUpdate = () => {
164+
// Make sure to always clear the debounce when `updateValue()`
165+
// is called, even when the v-model hasn't changed
166+
this.clearDebounce()
167+
// Define the shared update logic in a method to be able to use
168+
// it for immediate and debounced value changes
169+
const doUpdate = () => {
170+
value = this.modifyValue(value)
171+
if (value !== this.vModelValue) {
168172
this.vModelValue = value
169173
this.$emit('update', value)
174+
} else if (this.hasFormatter) {
175+
// When the `vModelValue` hasn't changed but the actual input value
176+
// is out of sync, make sure to change it to the given one
177+
// Usually caused by browser autocomplete and how it triggers the
178+
// change or input event, or depending on the formatter function
179+
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2657
180+
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3498
181+
/* istanbul ignore next: hard to test */
182+
const $input = this.$refs.input
183+
/* istanbul ignore if: hard to test out of sync value */
184+
if ($input && value !== $input.value) {
185+
$input.value = value
186+
}
170187
}
171-
const debounce = this.computedDebounce
172-
// Only debounce the value update when a value greater than `0`
173-
// is set and we are not in lazy mode or this is a forced update
174-
if (debounce > 0 && !lazy && !force) {
175-
this.$_inputDebounceTimer = setTimeout(doUpdate, debounce)
176-
} else {
177-
// Immediately update the v-model
178-
doUpdate()
179-
}
180-
} else if (this.hasFormatter) {
181-
// When the `vModelValue` hasn't changed but the actual input value
182-
// is out of sync, make sure to change it to the given one
183-
// Usually caused by browser autocomplete and how it triggers the
184-
// change or input event, or depending on the formatter function
185-
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2657
186-
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3498
187-
/* istanbul ignore next: hard to test */
188-
const $input = this.$refs.input
189-
/* istanbul ignore if: hard to test out of sync value */
190-
if ($input && value !== $input.value) {
191-
$input.value = value
192-
}
188+
}
189+
// Only debounce the value update when a value greater than `0`
190+
// is set and we are not in lazy mode or this is a forced update
191+
const debounce = this.computedDebounce
192+
if (debounce > 0 && !lazy && !force) {
193+
this.$_inputDebounceTimer = setTimeout(doUpdate, debounce)
194+
} else {
195+
// Immediately update the v-model
196+
doUpdate()
193197
}
194198
},
195199
onInput(evt) {

0 commit comments

Comments
 (0)