How to use/evoke to set in computed through methods? - vue.js

I am trying to update data property through computed property and found that it is impossible to set the value but I can use get/set to assign value in data property. Please see my example first.
data () {
return {
title: '',
color: null
}
},
computed: {
isTitle: {
get () {
return this.title
},
set () {
console.log('how can I come to this line?')
this.title = 'update title example'
}
},
isTitle() {
this.color = 'red'
return 'update title example'
}
},
mounted () {
this.getAccessToTitle()
},
methods: {
getAccessToTitle () {
if (isTitle) {
this.color = 'red'
}
},
example looks little bit weird but what I wanted to ask is..
when getAccessToTitle() is called through mounted, I assume, isTitle's set() should update the title in data property isn't it? I am not sure how can I use set in computed property when I call isTitle through methods but not template(I saw many examples that use template to call computed like https://vuejs.org/guide/essentials/computed.html#writable-computed but it is not what I am looking for!)
Thank you
this is what I wanted to do originally. update color in data and return title in isTitle. Tt works but was told that it is bad way to use computed so I added get/set
data () {
return {
title: '',
color: null
}
},
computed: {
isTitle() {
this.color = 'red' <---
return 'update title example' <---
}
},
mounted () {
this.getAccessToTitle()
},
methods: {
getAccessToTitle () {
if (isTitle) {
isColor(this.color)
}
},
isColor(val) {
// do something...
}

Related

Dynamically updating the passed parameter in the vue component

I have component:
<g :title="computeString"></g>
(standart element)
I use computed property to update it
computeString:{
get: function () {
console.log(this.cage.hitch);
return this.cage.hitch
},
set: function(newValue) {
return newValue;
}
},
But when I update the calculated field, the title is not updated.
How to dynamically update?
Try 2:
computeString:{
get: function () {
console.log(this.cage.hitch);
return this.cage.hitch
},
set: function(newValue) {
this.cage.hitch = newValue;
}
},
Not work.

Set data field from getter and add extra computed field

I wanted to set fields inside data using getters:
export default {
data () {
return {
medications: [],
}
},
computed: {
...mapGetters([
'allMedications',
'getResidentsById',
]),
I wanted to set medications = allMedications, I know that we can user {{allMedications}} but my problem is suppose I have :
medications {
name: '',
resident: '', this contains id
.......
}
Now I wanted to call getResidentsById and set an extra field on medications as :
medications {
name: '',
resident: '', this contains id
residentName:'' add an extra computed field
.......
}
I have done this way :
watch: {
allMedications() {
// this.medications = this.allMedications
const medicationArray = this.allMedications
this.medications = medicationArray.map(medication =>
({
...medication,
residentName: this.getResidentName(medication.resident)
})
);
},
},
method: {
getResidentName(id) {
const resident = this.getResidentsById(id)
return resident && resident.fullName
},
}
But this seems problem because only when there is change in the allMedications then method on watch gets active and residentName is set.
In situations like this you'll want the watcher to be run as soon as the component is created. You could move the logic within a method, and then call it from both the watcher and the created hook, but there is a simpler way.
You can use the long-hand version of the watcher in order to pass the immediate: true option. That will make it run instantly as soon as the computed property is resolved.
watch: {
allMedications: {
handler: function (val) {
this.medications = val.map(medication => ({
...medication,
residentName: this.getResidentName(medication.resident)
});
},
immediate: true
}
}

Binding an object from checkboxes

I need to bind an object from checkboxes, and in this example, a checkbox is its own component:
<input type="checkbox" :value="option.id" v-model="computedChecked">
Here's my data and computed:
data() {
return {
id: 1,
title: 'test title',
checked: {
'users': {
},
},
}
},
computed: {
computedChecked: {
get () {
return this.checked['users'][what here ??];
},
set (value) {
this.checked['users'][value] = {
'id': this.id,
'title': this.title,
}
}
},
....
The above example is a little rough, but it should show you the idea of what I am trying to achieve:
Check checkbox, assign an object to its binding.
Uncheck and binding is gone.
I can't seem to get the binding to worth though.
I assume you want computedChecked to act like an Array, because if it is a Boolean set, it will receive true / false on check / uncheck of the checkbox, and it should be easy to handle the change.
When v-model of a checkbox input is an array, Vue.js expects the array values to stay in sync with the checked status, and on check / uncheck it will assign a fresh array copy of the current checked values, iff:
The current model array contains the target value, and it's unchecked in the event
The current model array does not contain the target value, and it's checked in the event
So in order for your example to work, you need to set up your setter so that every time the check status changes, we can get the latest state from the getter.
Here's a reference implementation:
export default {
name: 'CheckBoxExample',
data () {
return {
id: 1,
title: 'test title',
checked: {
users: {}
}
}
},
computed: {
computedChecked: {
get () {
return Object.getOwnPropertyNames(this.checked.users).filter(p => !/^__/.test(p))
},
set (value) {
let current = Object.getOwnPropertyNames(this.checked.users).filter(p => !/^__/.test(p))
// calculate the difference
let toAdd = []
let toRemove = []
for (let name of value) {
if (current.indexOf(name) < 0) {
toAdd.push(name)
}
}
for (let name of current) {
if (value.indexOf(name) < 0) {
toRemove.push(name)
}
}
for (let name of toRemove) {
var obj = Object.assign({}, this.checked.users)
delete obj[name]
// we need to update users otherwise the getter won't react on the change
this.checked.users = obj
}
for (let name of toAdd) {
// update the users so that getter will react on the change
this.checked.users = Object.assign({}, this.checked.users, {
[name]: {
'id': this.id,
'title': this.title
}
})
}
console.log('current', current, 'value', value, 'add', toAdd, 'remove', toRemove, 'model', this.checked.users)
}
}
}
}

watching one value, computing the other one, how to update computed value when watched changes

I am watching one value and I computed another value.
Something like this:
computed: {
modeText: function () {
if(this.mode == 'create')
return 'Create'
else
return 'Edit'
}
},
watch: {
mode(val, old) {
if(val == 'create')
update modeText
else
update modeText
},
},
How do I recompute the computed value when watched value updates?
It seems like modeText is only dependent on mode, so instead of using computed, you can go for something simpler:
data: {
modeText: '',
mode: ''
},
watch: {
mode(val, old) {
this.modeText = this.updateModeText(val);
},
},
methods: {
updateModeText(val) {
if (val === 'create') {
return 'Create';
}
return 'Edit';
}
}

Vuejs2 issue passing data changes between children

Another issue with a project I am working on.
I have the following vuejs2 parent-child structure
Parent app
child product-list
product
product-image
colour-select
Within the product template I initiate the sibling components
The colourSelect component takes a comma delimited string and turns it into a drop down list. Whenever the selected option changes it emits the colour back to the product component which has a data variable "colour"
This appears to work fine.
The product-image component takes the product colour as a prop.
Whenever the colour changes I want the product-image component to detect it and trigger it to go get the relevant image. But its not detecting the change in colour.
Vue.component('product', {
props: ['productID', 'images', 'product'],
data: function () {
return {
colour: 'Navy',
}
},
computed: {
returnColour: function (colour) {
// this.colour = colour
//return colour
}
},
template: '<transition name="list"><li class="moving-item" id="productID">' +
'<product-image :productID="productID" :images="getImage(product.productID)" :colour="colour"></product-image>' +
'<colourSelect :colours="product.colour" :productID="product.productID" v-on:set-colour="setColour(colour)"></colourSelect>' +
'</li></transition>',
methods: {
getImage: function (listItemId) {
var images = this.images.filter(function (item) {
return returnCleanedData(item.Products_x003a_ID) === listItemId
})
},
setColour: function (colour) {
console.log('in main colour emit')
this.colour = colour
console.log(this.colour)
}
}
});
Vue.component('colourSelect', {
props: ['productID', 'colours', 'set-colour'],
template: '<select v-bind:id="getID()" class="form-control input-xs" :disabled=" isActive" v-bind:class="{disabledSelect: isActive}" v-on:click="setColour(productID)">' +
'<colourOption v-for="colourItem in colourArray">{{ colourItem.colour }}</colourOption>' +
'</select>',
data: function() {
return {
isActive: false
}
},
computed: {
colourArray: function () {
//splits data and applies it to the select
}
},
methods: {
getID: function () {
return 'colourSelect' + this.productID;
},
**setColour: function (productID) {**
//yeah used jquery here
var colour = $('#colourSelect' + productID).val()
this.$emit('set-colour', colour)
}
}
});
Vue.component('product-image', {
props: ['productID', 'images', 'colour'],
template: '<p><slot></slot><img :src="getImage(productID, images, colourSelected)" class="productImagePosition img-responsive img-rounded"></img></p>',
data: function () {
return {
isActive: false,
selectedColour: this.colour
}
},
computed: {
colourSelected: function () {
console.log('colour change detected')
return this.colour
}
},
methods: {
getID: function (test) {
return 'colourSelect' + this.productID;
},
getImage: function (listItemId, images, colour) {
console.log('selected colour')
console.log(colour)
//filter images to the specific colour and return link
},
}
});
The issue appears to be related to this line in the product template
v-on:set-colour="setColour(colour)"
When the child component emits the set-colour data back, the product is correctly running this method. But the product-image doesn't detect the change to its prop.
If i change the line to v-on:set-colour="setColour()" it will actually detect the change in the product-image but will error due to no data being passed.
Within the product-image component I have tried referencing a computed value (colourSelected) instead of the prop within the template which has no effect.
Any ideas?
Thanks
On product-image add a watcher to the colour prop:
watch: {
colour(value) {
// make changes here
},
},