so I have an error array in data and whenever user focuses out of an input it checks if its empty. If it is empty it add's an object to the error array like so:
[
"0": {
"product_name": {
"message": "to polje je obvezno"
},
"barcode": {
"message": "to polje je obvezno"
}
},
"1": {
"barcode": {
"message": "to polje je obvezno"
}
},
"2": {
"product_name": {
"message": "to polje je obvezno"
}
}
]
so the 0,1,2 stand for the index of the item because I have a v-for loop and then product_name or barcode stand for the input in that item/index.(component is at the end of the post if you need it). So now I am trying to display an error when product_name or barcode exists.
I am trying like this:
<span class="tooltip"
v-if="errors && errors[index] && errors[index]['product_name']" style="left: 5px">
test123 (this is product_name error, above index is the current index in v-for so 0 or 1 or 2...)
</span>
<span class="tooltip"
v-if="errors && errors[index] && errors[index]['product_name']"style="left: 5px">
test123 (this is barcode error, above index is the current index in v-for so 0 or 1 or 2...)
</span>
but it doesnt display the span
component:
<tr v-for="(item, index) in documentItems" :key="item.id">
<td>{{index 1}}.</td>
<td>
<div>
<textarea v-model="item.barcode"
@focusout="checkInput('barcode',index)"
cols="15" rows="2">
</textarea>
<span v-if="errors && errors[index] && errors[index]['barcode']">
test123
</span>
</div>
</td>
<td>
<div>
<textarea v-model="item.product_name"
@focusout="checkInput('product_name',index)"
cols="15" rows="2">
</textarea>
<span v-if="errors && errors[index] && errors[index]['product_name']">
test123
</span>
</div>
</td>
</tr>
EDIT: is it possible that my checkInput is the problem? this is how I created errors:
checkInput(name, itemIndex){
if(this.documentItems[itemIndex][name] == null){
this.errors[itemIndex][name] = { message: 'to polje je obvezno'}
};
//testing
console.log(this.errors[itemIndex][name]); //works
if(this.errors[1]['product_name']){
console.log("yes"); //works
}
},
EDIT2:
the spans show if I define error object like so:
errors: {
0: {
barcode: '',
product_name: ''
},
1: {
barcode: '',
product_name: ''
}
},
but if I do it with a for loop span don't show (I made a for loop in method where I retrive all the documentItems and gets fired on mounted()):
for(var i = 0;i < response.data.documentItems[0].length;i ){
this.errors[i] = {
barcode: '',
product_name: '',
}
}
CodePudding user response:
Your problem roots in a vue reactivity caveat mentioned in their documentation.
https://vuejs.org/v2/guide/reactivity.html#For-Objects
Vue will create proxy-like objects (a pattern similar to Observer using Object.defineProperty) for every field that is defined in your data function before anything runs, when you manually add fields using this.foo = bar
(or something similar), if 'foo' key is not already available in your data field, vue will not make it reactive, hence it will not update your DOM when it changes.
You can achieve what you want in a couple of workarounds.
First way which also mentioned in their documentations is to create whole errors object with Object.assign or spread syntax and re-assign your field in data.
// instead of `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
This solution is similar to treating a field like its immutable
So you can fix your checkInput method with the following change:
checkInput(name, itemIndex){
if(this.documentItems[itemIndex][name] == null){
const newErrorForName = { [name]: { message: 'to polje je obvenzo' }};
this.errors = Object.assign({}, {...this.errors, [itemIndex]: newErrorForName })
};
//testing
console.log(this.errors[itemIndex][name]); //works
if(this.errors[1]['product_name']){
console.log("yes"); //works
}
},
This is because vue cant understand manual object property add/delete.
Your second way is to use an array for errors instead of an object. This is probably a better idea since your errors object is really an array. it has fixed integer zero based indexes!