According to this post, it shouldn't be a problem to watch a puted property. And yet my code isn't working.
<template>
<div v-if="product" class="section">
<form>
<div class="control"><input type="text" class="input" v-model="title"></div>
<div class="control"><input type="text" class="input" v-model="description"></div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
title: null,
description: null
}
},
puted: {
product() {
// const payload = { collection: 'products', id: this.$route.params.productId }
// return this.$store.getters.objectFromId(payload)
console.log('working')
return { title: 'Awesome Title', description: 'Awesome Description' }
}
},
watch: {
product() {
this.title = this.product.title,
this.description = this.product.description
}
}
}
</script>
I'm expecting the watch
to trigger when product
is returned, but it doesn't.
I could set the properties in the puted property like so:
puted: {
product() {
const payload = { collection: 'products', id: this.$route.params.productId }
const product = this.$store.getters.objectFromId(payload)
this.title = product.title
this.description = product.description
return product
}
}
But then the piler gives me a warning: error: Unexpected side effect in "product" puted property
According to this post, it shouldn't be a problem to watch a puted property. And yet my code isn't working.
<template>
<div v-if="product" class="section">
<form>
<div class="control"><input type="text" class="input" v-model="title"></div>
<div class="control"><input type="text" class="input" v-model="description"></div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
title: null,
description: null
}
},
puted: {
product() {
// const payload = { collection: 'products', id: this.$route.params.productId }
// return this.$store.getters.objectFromId(payload)
console.log('working')
return { title: 'Awesome Title', description: 'Awesome Description' }
}
},
watch: {
product() {
this.title = this.product.title,
this.description = this.product.description
}
}
}
</script>
I'm expecting the watch
to trigger when product
is returned, but it doesn't.
I could set the properties in the puted property like so:
puted: {
product() {
const payload = { collection: 'products', id: this.$route.params.productId }
const product = this.$store.getters.objectFromId(payload)
this.title = product.title
this.description = product.description
return product
}
}
But then the piler gives me a warning: error: Unexpected side effect in "product" puted property
- What are you trying to achieve? There may be a more straightforward solution to your problem – Enrico Commented Jul 21, 2018 at 20:10
- I've updated my post to more clearly display intent. I'm trying to get a product and set some inital data() that are bound to some form inputs. I could set values within the pute function but I get this annoying side effect warning in the piler. I believe it's bad practice to set properties in a get? – HJo Commented Jul 21, 2018 at 20:16
-
1
You would need to use a watcher with
immediate
set in order to get your watcher to fire on the initial render. – Bert Commented Jul 21, 2018 at 21:14 - 1 @HamishJohnson you don't use puted for that. Have a look at created/mounted vue.js hooks. Inside them you can load external data and attach it to the current data model – Enrico Commented Jul 22, 2018 at 0:52
- 1 @Enrico Yeah I have to agree with you there - not really sure why I chose puted in this instance. Thanks – HJo Commented Jul 22, 2018 at 9:38
3 Answers
Reset to default 3Try the following:
watch: {
product: {
immediate: true,
handler(value) {
updateCode();
}
}
}
Accordingly to OP's ments, his intention is to get and load some initial data.
The mon way to achieve this behavior is to place it inside created or mounted
vuejs lifecycle hooks.
<template>
<div v-if="product" class="section">
<form>
<div class="control"><input type="text" class="input" v-model="title"></div>
<div class="control"><input type="text" class="input" v-model="description"></div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
title: '',
description: ''
}
},
created() {
this.getInitialData();
this.foo();
console.log("created!");
},
methods: {
getInitialData: function(){
const payload = {
collection: 'products',
id: this.$route.params.productId
};
var product = this.$store.getters.objectFromId(payload);
this.title = product.title;
this.description = product.description;
},
foo: function(){// ...}
},
}
</script>
Your structure is a bit all over the place. product
is a puted, so it runs whenever it's source values change. (You have no control over when it runs.) It shouldn't have side effects (assignments this.description
, this.title
), or trigger network requests.
The code in product
is fetching your source data. This belongs in methods
, linked explicitly to a user action or a lifecyle event.
Why do you need to copy your data (this.description = product.description
in watch:product
)? Vue works best when you have your data (your app state) outside Vue, in a global variable say. Then your Vue ponents just transparently reflect whatever the app state is at a given moment.
Hope this helps.