I have a form with many fields attached to a data - this.myData:
data: function() {
return {
isDataChanged: false,
myData: {},
myChangedData: {
default: '',
default1: {},
default2: []
},
}
},
myData is populated from a response from the server and it populates the form values.
myChangedData is for the new values, which are changed v-on:input="onChangeMyData($event, 'default')":
onChangeMyData(e, name, required = false){
const val = e.target.value.trim();
this.myChangedData[name] = val;
console.log(this.myChangedData)
this.checkIsmyDataChanged();
},
I can use the same method, providing a key as a second param. With the method checkIsmyDataChanged I am checking is it changed some field in the form. This method loops through myChangedData and compares its properties with changedData and if there is a difference this.isDataChanged = true.
The problem is that, I have a complicated structure of mydata/mydatachanged. default1 has objects in it and default1 is an array of objects. This means that, I can't use onChangeMyData, but other methods with different checks (validations) and now I need to call in all of them this.checkIsmyDataChanged();.
I created a watch for myChangedData:
watch:{
myChangedData: {
handler: function (newVal) {
console.log('change')
},
deep: true
},
},
, but it doesn't execute on change data
Did you try with Vue.set ? Source
Change this.myChangedData[name] = val; to
this.$set(this.myChangedData, 'name', val)
Thanks to that, the modification on the object should be detected and execute the watcher.
Related
I'm trying to save and read multiple json objects from my vue-application with the vue-cookie package (Version 1.1.4). The snippet below runs really well and the json object is saved and retrivied as expected.
However, I noticed as soon as the data is retrieved via cookies and i want to change data inside the object on the web page, the "updated" lifecycle method will not trigger. This behaviour is really awkward as I am only adding the cookieToJson() method to the beforMount() method. The Vue debugger also shows that the value is changed. I think the data is not reactive anymore, but how can I fix this.
data () {
return {
json: {
a: 0,
b: 1,
},
}
},
methods: {
jsonToCookie(name) {
const data = "{\"" + name + "\": " + JSON.stringify(this[name])+"}";
this.$cookie.set(name, data, { expires: '1M' }, '/app');
},
cookieToJson(name) {
const data = JSON.parse(this.$cookie.get(name));
if(data==null) return
for(var i = 0; i < Object.keys(data).length; i++) {
var name = Object.keys(data)[i]
this[name] = data[name];
}
},
beforeMount() {
console.log("beforeMount")
this.cookieToJson("json")
},
updated() {
console.log("updated")
this.jsonToCookie("json")
},
}
In case anyone run into a similar problem, I am using the localStorage now.
So I have a data options like this
data() {
return {
userPayload: {
description: '',
languageCodes: [],
facebookUrl: '',
youtubeUrl: ''
},
}
},
Later I applied some functions to fill out each attributes in data. Then when I want to submit the data using handleSaveData(), I passed this userPayload object to axios and turns out it's only read the value of description attributes.
handleSaveData() {
...
const userPayload = {
description: this.userPayload.description,
profile: {
languageCodes: this.userPayload.languageCodes,
facebookUrl: this.userPayload.facebookUrl,
youtubeUrl: this.userPayload.youtubeUrl
}
}
console.log(this.userPayload)
// this one contains value of all attributes
console.log(userPayload)
// this one only shows value of description attributes, while the others are empty string or empty array
// i expect it also return value of another attributes
// because i already access it with this.userPayload.{attributeName}
}
I already tried out deepClone userPayload object but it doesn't work
In my Vue component I have an array (of objects) prop called selectedSuppliers. I want to initialize a data prop called suppliers to selectedSuppliers, but any subsequent changes to suppliers should not propogate to selectedSuppliers.
I tried the following
props: {
selectedSuppliers: {
type: Array,
required: true
},
},
data () {
return {
selected: [...this.selectedSuppliers],
}
}
But it doesn't work. What is the correct way to initialize an array data property to an array prop?
If selectedSuppliers is an array of object, then the spread operator only performs a shallow copy of this array. It means that updating any object of suppliers will update the content of selectedSuppliers.
You can take a look at this short post.
This might work,
props: {
selectedSuppliers: {
type: Array,
required: true
},
},
data () {
return {
selected: this.selectedSuppliers.map(o => Object.assign({}, o)
}
}
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 have a requirement where it is necessary to have 2 levels of nesting in an object with state and type something like below
templates = {
type1: {
state1: [];
}
type2: {
state2: [];
}
};
However in one of the cases, I wont be having type but I need to select just based on state in this case. How to achieve this?
You could always add another item to your object wich defines the way it should be accessed.
template = {
// and then either
accessType : "type",
type1: {
state1: [];
},
type2:{
state2: [];
}
// or
accessType : "state",
state1: {
},
state2: {
}
}
Based on the accessType you can decide how you want to access the object.