I have a Vuex module with state like this:
const state = {
items: [],
selectedItem: {
id: null,
name: "",
}
}
And in my I let the user add the selectedItem to the items-array.
However, when I set the selectedItem I want to clear the old one, so I run a mutation that basically sets id and name to null. But this seems to clear the id and name of the selectedItem in the items array also!
My clearing mutation looks like this:
clearSelectedItem: function(state) {
state.items.selectedItem.id = null;
state.items.selectedItem.name = "";
},
To my understanding this should only clear the selectedItem outside of the items array, but it clears absolutely everything. Is there any syntax I can use to just get the single selectedItem?
I let the user add the selectedItem to the items-array.
It sounds to me like you are adding the object to the array by reference. Have you tried cloning the values into a new object and then adding the new object to the items-array instead?
Or you could try setting your clearing function to:
clearSelectedItem: function(state) {
state.items.selectedItem = {
id:null,
name:""
};
},
Related
I have read a lot of other topics regarding it but still have not got a solution.
I am trying to access a store state in my computed property and passing it as a prop to a child component. Changing that state is not triggering my computed property. It is still evaluating the old value.
Here is my computed property. I am trying to access a property in the state through a getter.
getRFQProjectStatus() {
if (this.project)
return this.$store.getters["RBViewStore/getRFQProjectStatus"](this.project.projectId);
return undefined;
},
I have even tried directly hardcoding the projectId instead of sending it through object, but still the same result.
My mutation:
setProjectStatus(state, { projectId, property = "", status }) {
console.log(property);
let project = state.projectsListView[projectId];
project.RFQProjectData.rfqProjectStatus = status;
var updatedRFQProj = Object.assign({}, state.projectsListView[projectId]);
Vue.set(state.projectsListView, projectId, updatedRFQProj);
},
Action
updateProjectStatus(store, { projectId, property, status }) {
store.commit("setProjectStatus", {
projectId,
property,
status,
});
console.log(store.getters.getRFQProjectStatus(projectId));
},
Getter
getRFQProjectStatus: state => projectId => {
if (state.projectsListView[projectId] && state.projectsListView[projectId].RFQProjectData && state.projectsListView[projectId].RFQProjectData.rfqProjectStatus)
return state.projectsListView[projectId].RFQProjectData.rfqProjectStatus;
return undefined;
}
state
export const state = {
projectsListView: {},
};
Printing my getter value after committing is printing the updated value. I am not sure what I am doing wrong. Any help is appreciated.
in the folowing code, after i update field collection it would not
update "this.fields" (which is bound to tha collection in store.js by
vuexfire rules) - only when i refresh page. please help. thanks
var newField = {
name: this.fieldName,
area: this.fieldArea,
farmId: this.farmId
}
var docRef = fb.field.doc()
docRef.set(newField)
var id = docRef.id
console.log(id)
fb.field
.doc(id)
.get()
.then(ref => {
this.$store.commit('updateCurrentField', ref.data())
})
How, and where, are you getting the this.fields?
Is it a computed property?
it should be somthing arround the lines of this in order to keep the data updated (vuex documentation)
computed: {
fields() {
this.$store.state.fields
}
}
I have this object of arrays that I'm tryin to watch every update of.
myData = {
"299":[527],
"376":[630,629]
}
I read this documentation on watching an object which instructed to use either this.$set(object, propertyName, value) or Object.assign({}, this.object, dataToBeAppended) to watch an object. I used this.$set.
export default {
...
data() {
return {
myData: {},
};
},
watch: {
myData(newVal) {
console.log(`🔴localStorage`);
},
},
methods: {
onFoldChange(propertyName) {
const newArr = [...]
this.$set(this.myData, propertyName, newArr);
},
}
}
Unlike what I expected, vue captures changes on property only. Changes in value to an existing property are not being watched. For example, if a property "299" was newly added, it will print 🔴localStorage. When the value of a property "299" is updated from [527] to something else, nothing is fired. When I print myData, I see every value updated correctly. It is just that watch isn't capturing the changes.
The documentation also described we can watch an array using this.$set(this.myData, indexOfItem, newValue) so I also tried array version of the above code, like this.
this.$set(this.myData[propertyName], index, newValueToAdd);
This time it doesn't listen at all. Not even the first entry.
Is there any better way to solve this issue? How do others watch an object? Is the complication coming from the type of values (array) ?
Currently, myData watcher observes only an object. Object contains pointers to arrays as in JS Objects & Arrays are passed by reference not by copy. That's why it can detect only changes in keys and with simple values. If you want to observe it deeper - I mean also those subarrays (or subobjects) - just use deep watch.
watch: {
myData: {
deep: true,
handler (newVal) {
console.log(`🔴localStorage`);
}
}
}
Another possible solution could be to use some Array.prototype operation to modify an array if it already exists. E.g:
methods: {
onFoldChange(propertyName) {
if (propertyName in this.myData && Array.isArray(this.myData[propertyName])) {
this.myData[properyName].push(162) // Some random value
} else {
const newArr = [...]
this.$set(this.myData, propertyName, newArr);
}
},
}
I am trying to update a single property of an object from an array using vuex.
here is my code in store file.
export default{
namespaced: true,
state: {
customers: null,
},
mutations: {
UPDATE_MODIFIED_STATE(state, value) {
state.customers = [
...state.customers.filter(item => item.Id !== value.Id),
value,
];
},
},
And below code is from my .vue file.
export default {
computed: {
customerArray() {
return this.$store.state.CustomerStore.customers;
},
},
methods: {
...mapMutations('CustomerStore', ['UPDATE_MODIFIED_STATE']),
updateCustomers() {
if(someCondition) {
this.customerArray.forEach((element) => {
element.IsModified = true;
this.UPDATE_MODIFIED_STATE(element);
});
}
/// Some other code here
},
},
};
As you can see I want to update IsModified property of object.
It is working perfectly fine. it is updating the each customer object.
Just want to make sure, is it correct way to update array object or I should use Vue.set.
If yes, I should use Vue.set, then How can I use it here.
You are actually not mutating your array, what you do is replacing the original array with a new array generated by the filter function and the passed value. So in your example there is no need to use Vue.set.
You can find more information about replacing an array in the vue documentation.
The caveats begin however when you directly set an item with the index or when you modify the length of the array. When doing this the data will no longer be reactive, you can read more about this here.
For example, consider the following inside a mutation:
// If you update an array item like this it will no longer be reactive.
state.customers[0] = { Id: 0, IsModified: true }
// If you update an array item like this it will remain reactive.
Vue.set(state.customers, 0, { Id: 0, IsModified: true })
I have a situation where I need to update data when it detects changes to a state. The user needs to be able to make further changes this info within a textarea. Using computed properties pulls in the data exactly how I want, but any changes made by the user after this are overridden because the computed property keeps changing this data back to it's initial values. What would be the best way to pull in data initially upon a state change but then allow for editing after that point?
Thanks!
Edit: Updated to what i've tried for #Libby.
<textarea v-model="exampleData"></textarea>
computed: {
...mapGetters({
item: 'item'
})
methods: {
exampleFunction() {
this.exampleData = this.item;
}
mounted() {
this.exampleFunction();
}
Update exampleData in a watcher for item:
watch: {
item(value) {
this.exampleData = value;
}
}
This way you can bind your exampleData to the textfield, but changes to the item will still affect it.
And if you want exampleData to be initially set to the value of item, do that in the component's mounted hook:
mounted() {
this.exampleData = this.item;
}
Here's a fiddle.
If you set your property indata, you can initialize it in mounted which only runs once when the page is loaded:
data:
text: null
mounted: ->
text = "This text is initialized"
And then set v-model on your textarea
<textarea v-model="text"></textarea>
So the value of the textarea will start out as "This text is initialized", but the user will be able to change it, and those changes will be saved in text
Vue already has a built-in solution to handle this if you use the getter/setter syntax for computed properties
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
As a result, when your state changes you can update the computer property by assigning it a value:
// state has changed in text area handler
this.fullName = 'new value'