Reputation: 462
I have a ngrx store with array of objects. What I am looking for is, update(modify) the object inside the array using the array index. My ngrx data will look like,
policies: {
beneficiaries: {
beneficiaries: [{
name: 'pqr'
age: 56
},
{
name: 'xyz'
age: 76
}
]
}
}
I have to update the beneficiary name based on the array index. So I have implemented the following reducer function
on(policiesActions.updateBeneficiaryPercentage, (state, action) => {
return {
...state,
beneficiaries: {
...state.beneficiaries,
beneficiaries: {
...state.beneficiaries.beneficiaries,
[action.index]: {
...state.beneficiaries.beneficiaries[action.index],
name: action.value
}
}
}
};
})
The issue with the above code is that after running this code the structure of my store is changing to
policies: {
beneficiaries: {
beneficiaries: {
0: {
name: 'pqr'
age: 1000
},
1: {
name: 'xyz'
age: 76
}
}
}
}
Please help me to fix the code so that I can update the value without altering the store structure.
Upvotes: 14
Views: 21927
Reputation: 1830
This is an easy way without resorting to deep diving into the state object.
on(ProductActions.updateProductSuccess, (state, action): ProductState => {
// define a constant and map over the existing state, inserting your new item,
// then assign your new object as the new state.
const updatedProducts = state.products.map(
product => action.product.id === product.id ? action.product : product);
return {
...state,
products: updatedProducts
};
}),
This assumes you are passing a complete product object in your success action.
Upvotes: 8
Reputation: 51
You can use immer.js to generate a new state without touching the previous state. No need to roll your own solution, plus recreating the object by cloning the previous one manually is error prone.
import produce from "immer"
on(policiesActions.updateBeneficiaryPercentage, (state, action) => {
return produce(state, draftState => {
draftState.policies.beneficiaries.beneficiaries[action.index].name = action.value
})
})
If you want to do it in a functional way you may try lenses example using ramda
Upvotes: 4
Reputation: 11283
When updating an object in array, I would re-create an array with all excluded objects and append last object which needs updated value.
const policies = {
beneficiaries: {
beneficiaries: [{
name: 'pqr',
age: 56
},
{
name: 'xyz',
age: 76
}
]
}
}
const updateObject = (state, action) => {
if(!state.beneficiaries.beneficiaries[action.index]) {
return state;
}
return {
...state,
beneficiaries: {
...state.beneficiaries,
beneficiaries: [
...state.beneficiaries.beneficiaries.slice(0, action.index),
{
...state.beneficiaries.beneficiaries[action.index],
name: action.value
},
...state.beneficiaries.beneficiaries.slice(action.index + 1)
]
}
};
}
console.log(updateObject(policies, {index: 1, value: 'test'}))
--Edit
Added the snippet and changed the logic so it doesnt change list order.
Upvotes: 10
Reputation: 15505
Use the Array.map
method:
arr.map((value, index) => index === action.index ? {...value, name: action.value} : value)
Or just use ngrx-etc, which lets you mutate your state in a mutable way while remaining immutable
mutableOn(onAction, (state, action) => {
state.arr[action.index].name = action.name
return state
})
Upvotes: 18