Vue2 Mutations Why just the first element is committed? - vuejs2

I have a store with the following mutation:
state{
itemsBought: [],
},
mutations: {
buyItemsInTheShop: (state, payload) =>
{console.log(payload)
state.itemsBought.push(payload)
}},
And a code in AlcoholShop.vue file:
computed: {
itemsBought() {
console.log("#itemsbought")
console.log(this.$store.state.itemsBought)
return this.$store.state.itemsBought;
}},
methods: {
...mapMutations(['buyItemsInTheShop']),
buyItems() {
console.log("#itemsToBeBought")
console.log(...this.itemsToBeBought)
this.buyItemsInTheShop(...this.itemsToBeBought);
this.tooglePages();
},
when I try to add more than one item to the cart I cannot do it only the first one is added - can anyone tell me why?
e.g. when I select two items and I console.log(...this.itemsToBeBought) I get an array of two objects but when I console.log(this.$store.state.itemsBought) only the first item is added.
How to fix it so that two items were added? I would be grateful for assistance.

Pass array to mutation:
this.buyItemsInTheShop(this.itemsToBeBought);
Then concat arrays:
state.itemsBought = state.itemsBought.concat(payload)

Related

Vuex passing different arrays

Making a filter:
Mutations
export default {
state: {
filteredBrands: []
},
mutations: {
showFilteredList(state, payload) {
state.filteredBrands.push(payload);
}
}
};
Methods
loadProducts(item) {
axios.get('/api', {
params: {
per_page: 20,
filter_machinery_brands: [ item ]
}
})
.then((response) => {
this.$store.commit(
'showFilteredList',
response.data
);
});
},
item this is an input with a checkbox, when clicked, a request is made to the server for this category
For some reason, the push does not work, why?
And I would like there to be a check, if the array is the same, then delete, otherwise add. Is it possible?
If you can se an array comes in as payload. Then you are trying to push an array into an array. Which cant be done in either js or ts.
You can try set the value:
state.filteredBrands = payload;
otherwise you would have to do something like this:
state.filteredBrands.push(payload[0]);
If you wanna control for existing items in array, and assuming your are not always setting value, but pushing new values into your array. You can do something like this:
if (state.filteredBrands.indexOf(payload[0]) === -1) {
// Not in array
state.filteredBrands.push(payload[0])
} else {
// is allready in array
state.filteredBrands.forEach((item, index) => {
if (item === payload[0]) {
state.filteredBrands.splice(index, 1)
}
})
}
EDIT:
My assumption was right.
Your payload is an array
Your state is an array
-------> You are trying to push payload(array) into state(array) - which cant be done i js - This solution would after my suggestion be more clean:
payload.forEach((value, index) => { // Looping payload
if (state.filteredBrands.indexOf(value) === -1) {
state.filteredBrands.push(value) // push if value not allready in array
} else {
state.filteredBrands.splice(index, 1) // if value is in array -> remove
}
})
Yes, you can push an array into an array.
I guess the problem here is your vuex config.
Vuex state is a function, so it needs to be:
state () {
return {
filteredBrands: []
}
}
And if you are using Nuxt:
export const state = () => ({
filteredBrands: []
})

Vuex getters forEach returns single value instead of multiple

I have a cart, and it's an array of products, I am trying to access every name in the cart.
I have forEach function in getters, but it returns just one name. I have tried.map() but it returns another array and I need multiple string values. Can you please help?
let cart = window.localStorage.getItem('cart')
const store = createStore({
state: {
cart: cart ? JSON.parse(cart) : [],
},
getters: {
setTitle: state =>{
let oneItem=''
state.cart.forEach((item)=>{
oneItem=item.ropeTitle
})
return oneItem
},
}
}
It's because you're returning just oneItem (let me guess, it's also the last item in the state.cart array as well?)
What you can try instead is using .join() to join the item together.
Let's say you want to join items by , , you can try
setTitle: state => state.cart.map(item => item.ropeTitle).join(', ')

Vue.js reactivity of complex objects in a store

My Problem
I am trying to store a list of complex items in a store and access these items from a component. I have a mqtt interface which receives data for these items and updates their values in the store. However, the ui does not react to updating the properties of these items.
Structure
In my store, i have two mutations:
state: {
itemList:{}
},
mutations: {
/// adds a new item to itemList
[ADD_ITEM](state, item) {
if (item&& !state.itemList[item.itemId])
{
Vue.set(state.itemList, item.itemId, item);
}
},
/// updates an existing item with data from payload
[SET_ITEM_STAT](state, { itemId, payload }) {
var item= state.itemList[itemId];
if (item) {
item.prop1 = payload.prop1;
item.prop2 = payload.prop2;
}
}
},
actions: {
/// is called from outside once when connection to mqtt (re-)established
initializeMqttSubscriptions({ commit, dispatch }, mqtt){
mqtt.subscribeItem("items/stat", async function(itemId, topic, payload) {
commit(SET_ITEM_STAT, { itemId, payload });
});
},
...
}
I also tried:
setting the item properties using Vue.set(state.itemList, itemId, item);
setting the item properties using Vue.set(state.itemList[itemId], 'prop1', payload.prop1);
I also want to show how i built the Component which accesses and displays these items (Item.vue). It is one component, that gets passed the itemId to show via the route params. I've got the following computed properties:
<template>
<div class="grid-page">
<h1 class="page-title">Item- <span class="fw-semi-bold">{{ id }}</span></h1>
<div>
<Widget v-if="item">
{{ item.prop1 }}
...
...
computed: {
id(){
return this.$route.params.itemId;
},
item(){
return this.$store.state.items.itemList[this.id];
}
}
So when the route parameter itemIdchanges, i successfully can see the item data, everything is fine. But if i update the properties of an item with the mutation shown above, no update in view is triggered.
I would be very happy if someone could give me a hint what i am doing wrong here. Thanks in advance!
Since i can't comment to ask for some clarifications,
If you're itemlist is an nested object, try out with Object.assign
[SET_ITEM_STAT](state, { itemId, payload }) {
var item= state.itemList[itemId];
if (item) {
this.state.itemList[itemId] = Object.assign({}, this.state.itemList[itemId].prop1, {payload.prop1})
this.state.itemList[itemId] = Object.assign({}, this.state.itemList[itemId].prop2, {payload.prop2})
// or
this.state.itemList[itemId] = Object.assign({}, this.state.itemList[itemId], {prop1: payload.prop1, prop2: payload.prop2})
}
}
Let me know how it goes
https://v2.vuejs.org/v2/guide/reactivity.html#For-Objects

Update entire item in array - redux

I am trying to update a single object in an array of objects with a redux dispatch, I have tried answers to similar questions however I cannot seem to get it working. What I want to do, is when the action comes in, it should look for an item in the array with the same date as the action.options.date it should then replace that item in the array with the new item actions.options.data[0] which is the whole item object.
const initialState = {
isFetching: false,
monthArray: [],
searchOptions: {
currentMonth: moment().format('YYYY-MM'),
leeway: 1
},
availabilityOptions: {
Early: -1,
Late: -1,
Day: -1,
Twilight: -1,
Night: -1
}
};
case UPDATE_DAY_IN_MONTH_ARRAY:
return Object.assign({}, state, {
monthArray: state.monthArray.map(item => {
if (formatDate(item.date) === formatDate(action.options.date)) {
return action.options.data[0];
}
return item;
})
});
Action code: (Reason for data: data[0] is because an array of objects from mysql is returned)
export const updateDayInMonthArray = (date, data) => {
return {
type: UPDATE_DAY_IN_MONTH_ARRAY,
options: {
date,
data: data[0]
}
}
}
Dispatching the action
const updateDayInMonthArrayHandler = (date, data) => {
dispatch(updateDayInMonthArray(date, data));
}
Figured it out, and thank you guys for help. Wasn't React or Redux issue, was actually an issue with the node server returning data before checking what was updated.

Update all object property of an array using vuex

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 })