I have encountered some issues what I don't understand. Can someone explain to me what I'm doing wrong?
I have a b-form-input and the variable "barcodeText".
<b-form-input id="barcodeInput" v-model="barcodeText" placeholder="Scan now"></b-form-input>
data() {
return {
barcodeText: ''
}
}
In addition I have this watch function:
watch: {
barcodeText(newVal, oldVal) {
if (newVal.length === 1 && newVal !== "I") {
console.log(this.barcodeText);
this.barcodeText = '';
}
if (newVal.length >= 9) {
console.log(this.barcodeText);
this.barcodeText = '';
}
}
}
However, when I input some text into the input field the console.log function in the first if-statement is called, but the variable "barcodeText" gets not assigned (The current value remains). When I type 9 characters the second if statement is called and the barcodeText gets assigned with the empty string. Now the weird part: When I change the assigned value in the first if-statement to 'abc' the value is assigned and everything works fine. Can someone explain to me why I can't assign an empty String in the first statement but in the second statement it works completely fine?
The issue you're seeing is a side-effect of Vue's reactivity system. When you're watching a property with a watcher, if you change the value of the property inside the watcher, it can cause the watcher to run again. This is because changing the property value causes Vue's reactivity system to trigger the watcher.
When you set this.barcodeText = ''
inside the watcher, it can cause the watcher to run again before the DOM has updated. This means this.barcodeText could still have its old value when the watcher runs again. This can lead to unpredictable behavior.
A solution is to use Vue.nextTick(), which can be used to delay the reset of the barcodeText until after the next DOM update cycle. Here's how you can do it:
watch: {
barcodeText(newVal, oldVal) {
if (newVal.length === 1 && newVal !== "I") {
console.log(this.barcodeText);
this.$nextTick(() => { this.barcodeText = ''; });
}
if (newVal.length >= 9) {
console.log(this.barcodeText);
this.$nextTick(() => { this.barcodeText = ''; });
}
}
}
The Vue.nextTick()
function is used to defer the execution of a function until the next DOM update cycle completes. It takes a callback function as an argument, and runs that function after the next DOM update cycle.
By wrapping the this.barcodeText = ''
in a Vue.nextTick()
, you're telling Vue to wait until after the current round of data changes have been processed and the DOM has been updated before it resets barcodeText. This should resolve the issue you're seeing.
or
you can use setTimeout()
to add a small delay, this is my way (it's a bad practice I guess) and its not a good way most of the time, you are guessing the time it takes to update in this case