I have a vue application where I watch an array for changes. This is working fine. But I'm not sure how to get the index of the array item which has changed, as the watch callback only passes in the old/new values.
Demo: http://jsfiddle.net/q3zd4fmv/
Simplified Example:
new Vue({
el: '#demo',
data: {
things: [{foo:1}, {foo:2}]
},
watch: {
things: {
handler: function (val, oldVal) {
alert('a thing changed')
},
deep: true
}
},
methods: {
change: function () {
this.things[0].foo = 5
}
}
})
Unfortunately, not out of the box. Using a combination of argument destructuring and a custom watch function, you can achieve something that should do it. For example;
new Vue({
el: '#demo',
data: {
things: [{foo:1}, {foo:2}]
},
methods: {
change: function (...args) {
let [thing, after, before] = args;
console.log(thing);
}
},
mounted: function(){
this.things.forEach(thing => {
this.$watch(() => thing, this.change.bind(null, thing))
});
}
})
Related
I am pretty new to watch and trying to figure out why my watch isn't triggering when accessing it as an object. I saw this thread, but it isn't clear to me if my problem is the same. Following is my simplified example (full example got more properties and properties with array
<div id="app">
<input type="text" v-model.lazy="userInfo.name"> {{userInfo.name}}
</div>
JS
new Vue({
el: "#app",
data: {
userInfo: {
name: ''
}
},
methods: {
},
watch: {
userInfo : {
name(oldVal, newVal){
console.log(oldVal +" " + newVal)
},
},
deep: true
}
})
Link to the JSFiddle
Change the watcher to something like this:
new Vue({
el: "#app",
data: {
userInfo: {
name: "null"
}
},
methods: {},
watch: {
"userInfo.name": function(oldVal, newVal) {
console.log(oldVal + " " + newVal);
}
}
});
Refer to the documentation for the same here.
Check the last example.
Here is a short example in your case:
new Vue({
el: "#app",
data: {
userInfo: {
name: 'null'
}
},
computed: {
name() {
return this.userInfo.name;
}
},
methods: {
},
watch: {
name(newVal, oldVal) {
alert(newVal);
alert(oldVal);
}
},
})
var vue_app = new Vue({
el: '#id1',
data: {
v1:[],
},
methods:{
pushUnique: function() {
this.v1.push({'id':1,'name':'josh'});
this.v1.push({'id':1,'name':'josh'}); //this should not work.
},
},
});
In above code the second push should not execute. I would like to keep id unique. How can this be done in Vue.
THanks
I would move to storing data in an object (keyed by id) and use a computed property to produce your v1 array. For example
data: {
v1obj: {}
},
computed: {
v1 () {
return Object.keys(this.v1obj).map(id => ({ id, name: this.v1obj[id] }))
}
}
Then you can use methods like Object.prototype.hasOwnProperty() to check for existing keys...
methods: {
pushUnique () {
let id = 1
let name = 'josh'
if (!this.v1obj.hasOwnProperty(id)) {
this.v1obj[id] = name
}
}
}
I have method that changes data in itself, simple example:
Vue.component('component', {
template: '#component',
data: function () {
return {
dataToBeWatched: ''
}
},
methods: {
change: function (e) {
var that = this;
setTimeOut(function() {
that.dataToBeWatched = 'data changed';
}, 2000);
},
makeSmthWhenDataChanged: function () {
// ajax request when dataToBeWatched changed or when dataToBeWatched isn't empty
}
}
});
How to create such watcher using correct methods vue js?
Or I need to use props watching it in component?
Vue components can have a watch property which is an object. The object keys need to be the name of the prop or data that needs to be watched, and the value is a function that is invoked when the data changes.
https://v2.vuejs.org/v2/guide/computed.html#Computed-vs-Watched-Property
Vue.component('component', {
template: '#component',
data: function () {
return {
dataToBeWatched: ''
}
},
methods: {
change: function (e) {
var that = this;
setTimeOut(function() {
that.dataToBeWatched = 'data changed';
}, 2000);
},
makeSmthWhenDataChanged: function () {
// ajax request when dataToBeWatched changed or when dataToBeWatched isn't empty
}
},
watch: {
dataToBeWatched: function(val) {
//do something when the data changes.
if (val) {
this.makeSmthWhenDataChanged();
}
}
}
});
Vue 2.2.6 version is used.
I have built very simple Vue instance and I want it to return the list of employees names. But the problem is that after getting /employees.json employees data is not being updated. I tried to debug it with console.log and it shows that inside loadData() function employees data is set correctly. But after this function is executed employees value becomes empty again.
var employees = new Vue({
el: 'employees',
template: "<ul id='employees'><li v-for='employee in employees'>{{ employee['name'] }}</li></ul>",
data: {
employees: []
},
methods: {
loadData: function () {
this.$http.get('/employees.json').then(response => {
this.employees = response.body;
//1. console.log returns here ">employees: [object Object]"
});
}
},
mounted: function (){
this.loadData();
//2. console.log returns here empty employees value
}
})
Where am I wrong? How correctly assign value from /employees.json to employees variable?
The console.log in mounted will return empty because the loadData is asynchronous, and will not have completed.
Your el isn't going to work because it needs a #: '#employees'
The template isn't going to work inline like that, because templates are for components. Where would it put it?
var employees = new Vue({
el: '#employees',
data: {
employees: []
},
methods: {
loadData: function () {
setTimeout(() => {
console.log('setting');
this.employees = [{name:'one'},{name:'two'}];
}, 800);
/*this.$http.get('/employees.json').then(response => {
this.employees = response.body;
//1. console.log returns here ">employees: [object Object]"
});*/
}
},
mounted: function (){
this.loadData();
}
})
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>
<ul id='employees'><li v-for='employee in employees'>{{ employee['name'] }}</li></ul>
I want to use a function as a data property. This seems to work fine as in the case of the 'works' data property. However I need the this context in the function so that I can calculate values stored in the this.shoppingCart (another property).
Is this possible? If so what am I doing wrong?
new Vue({
el: '#vueApp',
data: {
shoppingCart: [],
works : function () {
return "testfunc";
},
totalPriceCalcProperty : function () {
this.totalPrice = this.shoppingCart.reduce(function(total, cartItem){
console.log(total, cartItem);
return total + parseFloat(cartItem.price);
}, 0);
}
},
methods: {
totalPriceCalc: function () {
this.totalPrice = this.shoppingCart.reduce(function(total, cartItem){
console.log(total, cartItem);
return total + parseFloat(cartItem.price);
}, 0);
},
}
You should implement this by using methods, not data.
data is helping you to store something rather than handle some actions.
In methods, you can call this.xxx to get the properties from data or property