Vuejs2 - computed property in components - computed-properties

I have a component to display names. I need to calculate number of letters for each name.
I added nameLength as computed property but vuejs doesn't determine this property in loop.
var listing = Vue.extend({
template: '#users-template',
data: function () {
return {
query: '',
list: [],
user: '',
}
},
computed: {
computedList: function () {
var vm = this;
return this.list.filter(function (item) {
return item.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
})
},
nameLength: function () {
return this.length; //calculate length of current item
}
},
created: function () {
this.loadItems();
},
methods: {
loadItems: function () {
this.list = ['mike','arnold','tony']
},
}
});
http://jsfiddle.net/apokjqxx/22/
So result expected
mike-4
arnold-6
tony-4

it seems there is some misunderstanding about computed property.
I have created fork from you fiddle, it will work as you needed.
http://jsfiddle.net/6vhjq11v/5/
nameLength: function () {
return this.length; //calculate length of current item
}
in comment it shows that "calculate length of current item"
but js cant get the concept of current item
this.length
this will execute length on Vue component it self not on that value.
computed property work on other property of instance and return value.
but here you are not specifying anything to it and used this so it wont able to use any property.
if you need any more info please comment.

Related

How to use state in data function in vue

Having problem to use state in data function of Vue.
I tried this
this.items = this.$store.state.search_items
but it always results in an empty array like this
[__ob__: Observer]
length: 0
__ob__: Observer {value: Array(0), dep: Dep, vmCount: 0}
__proto__: Array
Any help would be appreciated. Thank you !!
Here is the mutation from which I am stating search_items
this is working because I am able to see state.search_items in Vue dev tool
SET_WORKSPACES(state, payload) {
state.workspaces = payload;
var items = [];
if (state.workspaces.length) {
state.workspaces.forEach(function(workspace) {
// Adding workspaces
if (workspace.portfolios.length) {
items = [...items, ...workspace.portfolios];
}
// Adding projects
if (workspace.projects.length) {
items = [...items, ...workspace.projects];
// Adding tasks
workspace.projects.forEach(function(project) {
if (project.tasks.length) {
items = [...items, ...project.tasks];
}
});
}
});
}
state.search_items = items;
}
Data property
data() {
return {
results: [],
keys: ['title','description'],
list:this.items,
}
},
If the state is updating correctly, the time taking for setting the state is making the issue. That means, the the function you're using to assign the state to data is rendering before the state set.
You can use a computed function that returning the state
computed:{
items : function(){
return this.$store.state.search_items;
}
}
Now you can use the computed function name items same like a data variable.

Vuejs: listen to props changes and use it

I am developing a project using Vue JS and I need to watch the props changes and call it inside a <span>.
I have used watch() and it shows that the props values are assigned.
But when I call it inside the <span> the value is not showing.
props: ['verifyText', 'verifyValue', 'profileId', 'logged', 'verifyType', 'status'],
watch: {
verifyText: function () { // watch it
this.verify_text = this.verifyText;
},
verifyValue: function () {
this.verify_value = this.verifyValue;
},
verifyType: function () {
this.verify_type = this.verifyType;
}
},
data() {
return {
verify_type: this.verifyType,
verify_text: this.verifyText,
verify_value: this.verifyValue,
}
},
//using inside span
<span>{{verify_text}}</span>
Receive and insert new data that changes from 'watch'
Try this.
props: ['verifyText', 'verifyValue', 'profileId', 'logged', 'verifyType', 'status'],
watch: {
verifyText: function (new_value) {
this.verify_text = new_value;
}
},
data() {
return {
verify_text: this.verifyText,
}
},
//using inside span
<span>{{verify_text}}</span>
I solved this issue by watching the verify_text in the parent component.
'verify_text': function (value) {
this.verify_text = value;
},
Same for the verify_type and verify_value
Thank you all for replying.

Vuejs: Can't access (computed) props within computed property loop

Perhaps an obvious one, but I have a Vue Single File Component like this:
<template>
...
</template>
<script>
export default {
props: [ 'matches', 'results' ],
computed: {
formattedMatches: function () {
let rows = [];
this.matches.forEach(function($match, $i) {
rows[$i] = {
id: $i + 1,
title: $match[0] + ' ' + $match[1]
};
});
return rows;
},
formattedResults: function () {
let rows = [];
this.results.forEach(function($resultRow, $i) {
rows[$i] = {
id: $i + 1,
title: this.formattedMatches[$i]
// Error in render: "TypeError: Cannot read property 'formattedMatches' of undefined"
};
});
return rows;
},
...
</script>
The error shows up also if I try with this.matches, not only with this.formattedMatches. I suppose it is a matter of variable scopes within classes and methods, but I do not even know if there is another better way or pattern to achieve that same behaviour.
Any ideas? Thanks in advance.
this has a different context in the anonymous function of forEach. Simplest fix is to use arrow function notation.
this.results.forEach(($resultRow, $i) => {
rows[$i] = {
id: $i + 1,
title: this.formattedMatches[$i]
};
});
Found the solution based on this other solution on StackOverflow.
As it says, "this inside a callback refers to the callback itself (or rather, as pointed out, the execution context of the callback), not the Vue instance. If you want to access this you either need to assign it to something outside the callback".
So in my case...
...
formattedResults: function () {
let self = this;
let rows = [];
this.results.forEach(function($resultRow, $i) {
rows[$i] = {
id: $i + 1,
title: self.formattedMatches[$i]
};
});
return rows;
},
...
... does the trick.
Thanks anyway!

How to populate empty array with a method in Vue

I'm trying to populate an empty array with a declared array variable in a computed function. I tried this but with no luck:
data: {
hashtags: []
},
computed: {
filteredHashtags () {
var defaultHashtags = [ '#hr', '#acc', '#sales' ];
var fHashtags =
_.chain( messages )
.pluck( 'hashtags' )
.flatten()
.map(
function ( tag ) {
return tag && tag.trim() ? '#' + tag : null; })
.filter( Boolean )
.value();
fHashtags = _.union( fHashtags, defaultHashtags );
return data.hashtags = fHashtags;
}
}
also, is there a better method to approach this?
A computed property isn't really a good use case for this, because the computed value has to be referenced in order for it to be called. Instead, just make it a method and call it the method when your Vue is created.
data: {
hashtags: []
},
methods: {
filterHashtags() {
// commented out stuff
// set the data property with the filtered values
this.hashtags = fHashtags;
}
},
created(){
this.filterHashtags();
}

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
},
},