Please refer to my snippet below. How can I get the old value of the changed model, in this case is the age in vuejs?
This solution assumes that you need the old value only when handling the change coming from user input, and not a generic model change - which is probably the case. Below I added a sketch of solution watching all changes in if it's necessary, though perhaps it's better to control the other changes at the places they occur, and not in this component.
v-model
and replace it with manual handling.It is important to note that "although a bit magical, v-model is essentially syntax sugar for updating data on user input events (...)". So without much harm you can remove it and handle the events directly, as you already almost do.
First, replace v-model
with :value
. The input will still follow the item.age
updates, but will not update the age automatically.
<input type="text" name="qty"
:value="item.age"
@change="changeAge(item,$event)">
Then, in order to actually update the value, add item.age = event.target.value
to changeAge
, like this:
changeAge: function(item, event){
alert(item.age); // Old value
alert(event.target.value); // New value
item.age = event.target.value; // Actual assignment
}
Note: you may want to use @input instead, that's what v-model actually uses.
And that's it, it should do the trick. If you need to prevent the change, you can just omit the assignment, however, you need to reset the input value. item.age = item.age
of Vue.set(item, 'age', item.age)
may do the trick, but I'm not quite sure it will.
Note: event.target.value
is a string, if you need a number, use parseInt()
.
In case you need to watch all the changes. However, if you need that, perhaps you should do that in some other place, not this component.
I don't have all the details ready, so I'll just the general draft: in your v-for
, instead of plain <input>
, you place another component, say <my-item>
. You put v-model=item
on it. Inside the component, you create the <input>
and forward the value
prop to it, as well as forward it's input
/change
events outside. In your component single item is a single prop, so you can attach a watcher directly to it. Relevant docs: Component Basics, Customizing Component v-model, Props.
replace v-model with value prop v-model is two-way binding, it will make your state complex then manually modify age property in change event
<input type="text" name="qty"
:value="item.age"
@change="changeAge">
export default {
change(val) {
let ov = this.item.age
let nv = val
// do something
// this.item.age = nv
}
}
It may be too late. This worked for me as long as the function name inside the watch object is named as the variable which is watched. It only watches the specific variable.
watch:{
items: function(newVal, oldVal){
console.log("New value: "+ newVal + ", Old value: " + oldVal);
},
other_variable: function(newVal, oldVal){
console.log("New value: "+ newVal + ", Old value: " + oldVal);
}
}
https://vuejs.org/v2/api/#Vue-nextTick
changeAge() {
this.$nextTick(() => {
// here the current values are set, do desired actions
})
}
You dont get old value of element on-change as explained here. Also when watching an object, you can not get older value as explained here until the reference of object changes.
To work around these you can create a computed property which will be clone of your items
data, and you can put a watcher over this computed property to get to know the old value as well, See working code below:
var app = new Vue({
el:"#table1",
data:{
items:[{name:'long name One',age:21},{name:'long name Two',age:22}]
},
watch:{
clonedItems: function(newVal, oldVal){
alert(JSON.stringify(newVal));
alert(JSON.stringify(oldVal));
}
},
computed:{
clonedItems: function(){
return JSON.parse(JSON.stringify(this.items))
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<table class="table table-cart" id="table1">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in items">
<td>{{item.name}} :</td>
<td>
<input type="text" name="qty"
v-model="item.age">
</td>
</tr>
</tbody>
</table>
You can simply use
<input type="text" name="qty" v-model="item.age" @change="changeAge($event)">
and
changeAge: function(event){
item = event.target.value; // Actual assignment
}
in vue method object