0👍
For example, assuming the initial value for this.tabs='1'
, if this.edit
is true, and let this.tabs='11'
, so the newVal of the watch will be '11'
, and oldVal of the watch will be '1'
; then this.tabs
will be changed to this.tabs='1'
because of this.edit
is true. now newVal='1', oldVal='11'
, finally it will fall into one infinite loop.
Vue.config.productionTip = false
new Vue ({
el:'#app',
data () {
return {
tabs: '1',
edit: true
}
},
watch: {
tabs: function (newVal, oldVal) {
console.log(newVal, oldVal)
if (this.edit) this.tabs = oldVal
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div>
<div>
<input type="text" value="A" v-model="tabs">
</div>
<pre>{{tabs}}</pre>
</div>
</div>
One workaround is uses the setter of one computed property.
Vue.config.productionTip = false
new Vue ({
el:'#app',
data () {
return {
tabs: '1',
edit: true,
tabsCopy: this.tabs
}
},
computed: {
myTabs: {
get: function () {
return this.tabs
},
set: function (newVal) {
if (this.edit) {
this.$forceUpdate()
return
}
this.tabs= newVal
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div>
<div>
<input type="checkbox" v-model="edit">
<input type="text" v-model="myTabs">
</div>
</div>
</div>
Another solution is perform the validation in @input.
Vue.config.productionTip = false
new Vue ({
el:'#app',
data () {
return {
tabs: '1',
edit: true,
tabsCopy: this.tabs
}
},
methods: {
changeValue: function (newVal) {
if(this.edit) { this.$forceUpdate(); return}
this.tabs = newVal.target.value
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div>
<div>
<input type="checkbox" v-model="edit">
<input type="text" :value="tabs" @input="changeValue($event)">
</div>
</div>
</div>
The worse workaround is uses one data property to check if newVal matches it, if yes, return immediately.
Anyway, it is not a good idea to use one watch to determinate its watch object if need to be changed or not.
So uses the solution setter of computed property will be better.
Vue.config.productionTip = false
new Vue ({
el:'#app',
data () {
return {
tabs: '1',
edit: true,
tabsCopy: this.tabs
}
},
watch: {
tabs: function (newVal, oldVal) {
if (newVal == this.tabsCopy) return
if (this.edit) {
this.tabs = oldVal
this.tabsCopy = this.tabs
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div>
<div>
<input type="checkbox" v-model="edit">
<input type="text" v-model="tabs">
</div>
</div>
</div>
Source:stackexchange.com