I have an Array "contracts" in which there are arrays of each contract information.
On the editing page I'd like to have the Info which contract was edited.
new Vue({
data(): {
return {
contracts: [
{name:"a",changed:false},{name:"b",changed:false}
]
}
},
watch: {
contracts: {
handler: function(val) {
this.contracts[x].changed=true;
},
deep=true
}
}
});
I simply want to find "x", the Index of the changed Array. The number of contracts is variable so watching every single one wouldn´t work.
Related
Vue dont see changes in simple array items.
I am learning Vue.js and have problem with watcher.
Namely i am trying to watch changes in array, and change one data value.
Every time i add a new item and change or delete an existing item, I want to change the value.
data() {
return {
change: false,
array: ['one','two','three','four']
}
},
watch:{
array:{
deep:true,
handler(){
this.change = true;
}
}
}
Vue just see when array length is changed but not particular element.
You can watch nested values in an object as shown in the docs use a dot-like-string notation.
var vm = new Vue({
data: {
e: {
f: {
g: 5
}
}
},
watch: {
// watch vm.e.f's value: {g: 5}
'e.f': function (val, oldVal) { /* ... */ }
}
})
To my knowledge you CANNOT do this with arrays (i.e. array[0]) because the reference my shift or be removed. I think the best way to do what you want is to compare the newValue and oldValue in the watcher handler function if the whole array changes.
// from vuejs docs
watch: {
// whenever question changes, this function will run
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
I'm trying to have a component which can change some elements in it. In reality, a change will be like swapping the object in a given position. I did some POC and tried to do the reverting method to be able to leave it how it was before.
export default {
name: 'Landing',
data () {
return {
items: [
{
id: 1,
category: 'Something something'
},
{
id: 2,
category: 'Something something'
}
]
};
},
created() {
this.originals = this.items.slice(0);
},
methods: {
change() {
this.items[0].category = 'Changed';
},
revert() {
// ??
}
}
};
I've tried a couple of things especially after reading this: https://vuejs.org/2016/02/06/common-gotchas/#Why-isn%E2%80%99t-the-DOM-updating
while (this.snacks.length) {
this.items.pop();
}
this.originals.slice(0).forEach(o => this.items.push(o));
But it doesn't work. If I delete the pushing part, I get an empty list correctly but if I try somehow to push it back, it won't work.
What am I missing here?
If you give a working fiddle I can show you what happened.
Basically, because you are modifying the same array object. this.originals refers to the same array as this.items
Slice returns a shallow copy of the object. You should either take a deep copy or your revert should be the one initializing the object.
this.items.pop();
will remove the items from this.originals as well.
Hello there my problem is that I want to add two functions, and the sum I want to put it in another array; do I need the revenue as an array or if I let it as a function is fine? I thought also that it would be better to assign the numa in function as an array because of that button.
Also, when i trie to put it like this.functionA+this.functionB the result is ,.
Basically, the whole idea is that i need to calculate a revenue for each month so I added a button and made arrays to parse in the results and then project them.
The code of is the following:
export default{
name: 'Home',
data(){
return{
FormData: {
revenue:[
{
lollipops:[
{
lolliSold:0,
pricePerLolli:0,
}
],
chocolate:[
{
numchocoSold:0,
pricePerChoco:0,
}
],
numa:0,
oprod:0
}
] }}
computed: {
lolliesSale(){
let SaleArray=[];
this.FormData.revenue.forEach((ItemL, indexL)=>{
SaleArray[indexL]=ItemL.lollipops[0].lolliSold+ItemL.lollipops[0].pricePerLolli;
});
return SaleArray;
},
chocolateSale(){
let choSaleArray=[];
this.FormData.revenue.forEach((ItemC, indexC)=>{
choSaleArray[indexC]=ItemC.chocolate[0].numchocoSold*ItemC.chocolate[0].pricePerChoco;
});
return choSaleArray;
},
numaSupport(){
let numaSuppArray=[];
this.FormData.revenue.forEach((ItemN, indexN)=>{
numaSuppArray[indexN]=ItemN.numa;
});
return numaSuppArray;
},
revenue(){
//return this.<anyfunction>; <- this is ok!!!!
}
ok, so create an array monthlyRevenues: [],
at the end of each month, push totalRevenue into the array and set totalRevenue to zero. you can do the same with any items you have in the store. then use a v-for each item in monthlyRevenues and display them on the page {{item}}
Im not sure exactly what you are trying to achieve here.
It seems like you want to keep track of total revenue, and how much of each item is sold. I dont understand why you have arrays in your data. all you need is a single variable for each of the things you are tracking.
Data() {
return {
chocPrice: 5,
lolliPrice: 5,
otherPrice: 1,
totalRevenue: 0,
lolliSold: 0,
chocSold: 0,
create a button that will trigger a method.
<button v-on:click="buyChocolate">Buy Chocolate</button>
whenever a chocolate/lollipop is sold you can trigger a method that will increment your totalRevenue by the price of that item as well as increment the number of chocolate/lollipop sold
chocSold++, totalRevenue = totalRevenue+chocPrice.
then you can render those items on the page with something like {{totalRevenue}}
the numa computed function to make an array it doesn't need since for each Year I have only one numa(=other Income)
so, in revenue I reference to the previous functions in the corresponding index, the index shows the position of the array.
export default{
name: 'Home',
data(){
return{
FormData: {
revenue:[
{
lollipops:[
{
lolliSold:0,
pricePerLolli:0,
}
],
chocolate:[
{
numchocoSold:0,
pricePerChoco:0,
}
],
numa:0,
oprod:0
}
] }}
computed: {
lolliesSale(){
let SaleArray=[];
this.FormData.revenue.forEach((ItemL, indexL)=>{
SaleArray[indexL]=ItemL.lollipops[0].lolliSold+ItemL.lollipops[0].pricePerLolli;
});
return SaleArray;
},
chocolateSale(){
let choSaleArray=[];
this.FormData.revenue.forEach((ItemC, indexC)=>{
choSaleArray[indexC]=ItemC.chocolate[0].numchocoSold*ItemC.chocolate[0].pricePerChoco;
});
return choSaleArray;
},
revenue(){
let revenueArray=[];
this.FormData.revenue.forEach((rItem, indexR)=>{
revenueArray.push(this.lolliesSale[indexR] + this.chocolateSale[indexR] + this.FormData.revenue[indexR].numa);
});
return revenueArray;
}
I've made my filters section using vue.js. I inject all the components through ajax and they response dynamically to those filters. Components in my case represent cars, they have price, marks, etc...
Now I'd like to add two more filters that allow me to sort them by some field (price, for instance). I've been reading and it's quite easy to sort lists specifying a field and a order...
How should I proceed to create that list and so, being able to sort it.
Here I made a little fiddle, very simple, in which I'd to sort the cars by prize once I click the filter.
var Car = Vue.extend({
template: '#template_box_car',
props: {
show: {
default: true
},
code: {
default: ""
},
prize: {
default: 0
},
description: {
default: "No comment"
}
}
});
//register component
Vue.component('box_car',Car);
//create a root instance
var vm = new Vue({
el: 'body',
methods: {
sortBy: function(field, order){
}
}
});
First, store the data for each car component in a data property in the parent component:
data: function () {
return {
cars: [
{ code: '11A', prize: 5.00, description: 'Ford Ka' },
{ code: '11B', prize: 3.00, description: 'Kia ceed' },
{ code: '11C', prize: 6.00, description: 'Ford Ka' },
{ code: '13A', prize: 45.00, description: 'Mercedes A' },
{ code: '17B', prize: 20.00, description: 'Seat Leon' },
]
}
},
Then, use the v-for directive to create a box_carcomponent for each of the objects in your cars data property:
// In your version of Vue.js it would look like this:
<box_car
v-for="car in cars"
:code="car.code"
:prize="car.prize"
:description="car.description"
:track-by="code"
></box_car>
// In newer versions of Vue.js, you can pass each object to the `v-bind` directive
// so you don't need to explicitly set each property:
<box_car v-for="car in cars" v-bind="car" :key="car.code"></box_car>
Then, in your sortBy method, simply sort the cars array:
// I used lodash, but you can sort it however you want:
methods: {
sortBy: function(field, order) {
this.cars = _.orderBy(this.cars, field, order);
}
}
Here's a working fiddle.
I think I may have an odd use case here. I've got a Code model with code, title, description attributes. Users are documenting work (healthcare), they enter the code, say 7, and 7 always means that something particular happened, say "The patient was cured." Whatever, doesn't matter. Point is, I don't want to bother saving the title and description in every model, but I want to be able to pull them for displaying.
So the API delivers an array of codes like [ 1, 13, "A4" ]. I'm trying to use both can.Model.parseModel and can.Map.define to coerce that array into Code models, but I'm having a hard time.
Why is parseModel, parseModels never called in this example? fiddle
Code = can.Model.extend({
parseModel: function(data) {
// return { code:data }
console.log('Never hit!');
},
parseModels: function() {
// ...
console.log('Never hit!');
}
},{
_title: can.compute(function() {
// return title from cached lookup
})
});
Model = can.Model.extend({
findAll: 'GET /Models'
},{
define: {
Codes: {
Type: Code.List
}
}
});
can.fixture('GET /Models', function() {
return [
{ Codes: [1,2,3] }, // I want to turn each number into an object
{ Codes: [4,5,6] },
{ Codes: [7,8,9] }
];
});
Model.findAll({});
.parseModels is only called during retrieval of CRUD service data.
To make your example work, you have to make a Model.parseModel convert each Code array to an an array of objects.
Alternately, you could change Model's define.Codes.Type to something like:
Codes: {
type: function(newVal){
if(newVal instanceof Code.List) {
return newVal
} else {
return new Code.List( newVal.map(function(num){ return {value: num}}) )
}
}
}