I have a computed property function called: Total, this essentially calculates the name + value pairs of an array called prices, it's for a quotation form whereby a running total is added up as a user progresses through a multi-step form, values are then pushed into an array to keep things clean.
This computed property allows me to echo the total on the page which is dynamically updated without any additional code, I can simply add total using handlebars to wherever I want on my page like so: {{ total }}
The problem I'm now facing is that I also want the value of 'total' to be included in a separate array, or at least added to an array and I can't seem to get it right.
The working code which gets the values of my prices array which is by default empty is as follows:
computed: {
total: function(){
var total = [];
Object.entries(this.prices).forEach(([name, value]) => {
total.push(value)
});
return total.reduce(function(total, num){
return total + num
}, 0);
}
}
I want to do add something like this to my computed property:
this.quote.totalPrice = total
I've tried:
computed: {
total: function(){
var total = [];
Object.entries(this.prices).forEach(([name, value]) => {
total.push(value)
});
return total.reduce(function(total, num){
return total + num
this.quote.totalPrice = total
}, 0);
}
}
I'm not getting anything with this?
You can use a watcher to keep track of changes to your computed property and update any variables accordingly:
watch: {
total(newTotal) {
this.quote.totalPrice = newTotal
}
}
Related
I have an empty object data property
data() {
return {
chosen: {},
}
}
Then I have a computed property the results of which are related with chosen property.
myComputed() {
let result = 0
Object.entries(this.chosen).forEach(([key, value]) => {
result = result + value
})
return result
}
Then I have a method that actually changes the chosen property
setChosen(someValue) {
this.chosen['key'] = someValue
}
So when I call setChosen and adding a new value the myComputed is not executed and not updating my view value.
I believe it's caused by your computed method not detecting the change, read more here: https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
Try the folowing:
setChosen(someValue) {
// IF no key is parsed
this.$set(this.chosen, 'key', someValue)
// IF key is parsed
// this.$set(this.chosen, key, someValue)
}
Obviously if someValue is only the value, you need to wrap the 'key' in quotes to directly name it: key. If your function is parsed a second value as a string, just use that directly.
Reactively set the new value
I had an API call to the backend and based on the returned data, I set the reactive data dynamically:
let data = {
quantity: [],
tickets: []
}
api.default.fetch()
.then(function (tickets) {
data.tickets = tickets
tickets.forEach(ticket => {
data.quantity[ticket.id] = 0
})
})
Based on this flow, how can I set watcher for all reactive elements in quantity array dynamically as well?
You can create a computed property, where you can stringify the quantity array, and then set a watcher on this computed property. Code will look something like following:
computed: {
quantityString: function () {
return JSON.stringify(this.quantity)
}
}
watch: {
// whenever question changes, this function will run
quantityString: function (newQuantity) {
var newQuantity = JSON.parse(newQuantity)
//Your relevant code
}
}
Using the [] operator to change a value in an array won't let vue detect the change, use splice instead.
I have a paginated record set from a http response and want to further implement client side pagination on return paginated record set, thus I have the following component markup
<td v-for="item in items">....</td> // only print 5 at a time
and in the default....
{
data: { return {
itemsData:[] // populated from RESTful data in increments of 20
, offset: 0 // for internal pagination
} },
computed: {
items: function(){
return this.itemsData.slice(this.offset, 5); // re-populate over time as offset changes
}
},
methods: {
getItems: function() {
this.$http.get('/api/items/?page=' + this.page).then(response=>
{
this.itemsData = response.data.data; // json array and I al get back meta data
// for which i use in a mixin to calculate offset and page etc.
// for both client side and server side pagination
}) // fetches records 20 at a time
}
}
.........
If itesmData is populated and then offset is dynamically changed. Shouldn't the component's template re-rendered with a new items collection?
Or should I be using a method instead? e.g.
<td v-for="item in paginated(itemData)">....</td>
{
....
methods: {
paginated: function(items){
var arr=[];
for( var i = this.offset; i < this.offset + 5; i++)
arr.push(item[i]);
return arr;
}
}
How would the template be updated with the new array? Would I need to implement a watcher? on the computed data? or would the offset do?
UPDATE:
I tried to implement the pagination via competed and while I get the template to render the first 5..... in trying to re-render after updating offset does not fire.... arr seems to return empty even thought i am on the second page and offset is yet to reach itemsData.length
Can you iterate through a data array property OUTSIDE of the template? i.e. loop through this.itemsData[i] or this.$data.itemsData[i]???
You need to make following changes in your code:
computed: {
items: function(){
return this.itemsData.slice(this.offset, this.offset + 5); // re-populate over time as offset changes
}
}
As you can see from documentation, slice takes two argument start and end, it will return a portion of an array into a new array object selected from start to end (end not included).
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.
I need to check variable rasters_previews_list for changing. Here is my code:
var userContent = Vue.extend({
template: '<p>Some template</p>',
data: function () {
return {
rasters_previews_list: []
}
},
watch: {
'rasters_previews_list': function(value, mutation) {
console.log("Value changed");
}
}
});
But In console I do not see Value changed when it got new data.
Data changing function:
map.on('draw:created', function (e) {
//...
Vue.http.post('/dbdata', DataBody).then((response) => {
userContent.rasters_previews_list = response; // putting JSON answer to Component data in userContent
console.log(response);
}, (response) => {
console.log("Can't get list rasters metadata from DB. Server error: ", response.status)
});
I change value in map.on('draw:created', function (e) (Leaflet JS). I see console.log output, so seems data is changing.
If you want to change the value of an array you will have to use the special Array extension methods Vue.set and Vue.delete.
Due to limitations of JavaScript, Vue cannot detect the following changes to an Array:
When you directly set an item with the index, e.g. vm.items[0] = {};
When you modify the length of the Array, e.g. vm.items.length = 0.
https://vuejs.org/api/#Vue-set
This problem is also mentioned in the common gotchas
When you modify an Array by directly setting an index (e.g. arr[0] = val) or modifying its length property. Similarly, Vue.js cannot pickup these changes. Always modify arrays by using an Array instance method, or replacing it entirely. Vue provides a convenience method arr.$set(index, value) which is just syntax sugar for arr.splice(index, 1, value).