Reputation: 3568
I have a "products" array with multiple objects. Each product object contains the property "price". I want to watch this property in each product for possible changes. I am using this to calculate a commission price when the user changes the price in an input box.
My products array looks like this;
[
0: {
name: ...,
price: ...,
commission: ...,
},
1: {
name: ...,
price: ...,
commission: ...,
},
2: {
name: ...,
price: ...,
commission: ...,
},
...
...
...
]
I've tried this, but it doesn't detect any changes except for when the products are first loaded;
watch : {
// Watch for changes in the product price, in order to calculate final price with commission
'products.price': {
handler: function (after, before) {
console.log('The price changed!');
},
deep : true
}
},
The products are loaded like this;
mounted: async function () {
this.products = await this.apiRequest('event/1/products').then(function (products) {
// Attach reactive properties 'delete' & 'chosen' to all products so these can be toggled in real time
for (let product of products) {
console.log(product.absorb);
Vue.set(product, 'delete', false);
Vue.set(product, 'chosen', product.absorb);
}
console.log(products);
return products;
})
}
Other questions I've looked at Vue.js watching deep properties This one is trying to watch a property that does not yet exist. VueJs watching deep changes in object This one is watching for changes in another component.
Upvotes: 4
Views: 2177
Reputation: 1610
You can't really deep-watch products.price
, because price is a property of individual product, not the products array.
Declarative watchers are problematic with arrays, if you attempt to use an index in the watch expression, e.g products[0].price
, you get a warning from Vue
[Vue warn]: Failed watching path: “products[0].price”. Watcher only accepts simple dot-delimited paths. For full control, use a function instead.
What this means is you can use a programmatic watch with a function, but it's not explained all that well.
Here is one way to do it in your scenario
<script>
export default {
name: "Products",
data() {
return {
products: []
};
},
mounted: async function() {
this.products = await this.apiRequest('event/1/products')...
console.log("After assigning to this.products", this.products);
// Add watchers here, using a common handler
this.products.forEach(p => this.$watch(() => p.price, this.onPriceChanged) );
// Simulate a change
setTimeout(() => {
console.log("Changing price");
this.products[0].price= 100;
}, 1000);
},
methods: {
onPriceChanged(after, before) {
console.log(before, after);
}
}
};
</script>
Here is my test Codesandbox (I use color instead of price because there's no price in the test api)
Upvotes: 2