Object spread operator: Set property to be updated via payload [duplicate] - javascript

This question already has answers here:
How to use a variable for a key in a JavaScript object literal?
(16 answers)
Closed 4 years ago.
Code snippet:
updateSelectedAreaColor: (state, payload) => {
state.selectedArea = { ...state.selectedArea, color: payload };
},
I'm updating the property color of the object state.selectedArea with a payload. Instead of hard-coding the property to be updated, I would like to set the property through my payload. For example:
updateSelectedAreaColor: (state, payload) => {
state.selectedArea = { ...state.selectedArea, payload.target: payload.value };
},
However, this code throws an error. Does anyone know how I can set the value to be updated via the payload?

Dynamic properties go into brackets:
updateSelectedAreaColor: (state, payload) => {
state.selectedArea = { ...state.selectedArea, [payload.target]: payload.value };
},
However I would prefer:
updateSelectedAreaColor: (state, payload) => {
state.selectedArea = { ...state.selectedArea, ...payload};
},
That way, you can easily change multiple props at the same time:
updateSelectedAreaColor(this.state, { color: "green", backgroundColor: "red" });

Related

Problems achieving required result of using the spread (...) operator with state object

I have a pimRegistration state initialization as shown in the chrome redux-devtools screen capture below. The nesting being referenced is pimRegistration (state.domain.patient):
I updated the patient.name object with the following spread operator statement:
store.update((state) => ({
...state,
...patientPath,
...{ [property]: value },
}));
...where property is the "name" property of the patient object with value. After the update, the following screenshot shows the new state:
Note that the original patient object (purple in the screenshot) is updated with the name object, duplicated and placed at the root of the state (yellow in screenshot).
I would like to overwrite the properties of the pimRegistration(state).domain.patient object, not to create a new patient object.
The state update is called as shown below.
store.update((state) => ({
...state,
...patientPath, // state.domain.patient
...{ [property]: value },
}));
I have tried my different combinations without achieving the desired result.
The complete update function is shown below.
update(property: string, path: string, value: any) {
const paths: string[] = path.split(".");
const pathReducer = (state: IRegistrationState, path_: string) => {
if (paths.length <= 0) {
return state.domain;
}
return state[path_];
};
const domainPath = state.domain;
let patientPath, nokPath, referrerPath;
if (path.includes("patient")) {
patientPath = paths.reduce(pathReducer, state);
}
if (path.includes("nok")) {
nokPath = paths.reduce(pathReducer, state);
}
if (path.includes("referrer")) {
referrerPath = paths.reduce(pathReducer, state);
}
store.update((state) => ({
...state,
...patientPath,
...{ [property]: value },
}));
}
The function above is invoked with the following statement in Angular 2.
if (this.path.includes("patient")) {
this._repo.update("name", "domain.patient", this.name);
}
Thanks
Deep updates to a store can be tricky. In your function you seem to be spreading the updates at the root rather than at the level you want the update at. This answer here outlines the usual practice to update the state. In short, something like
const newState = {
...state,
domain: {
...state.domain,
patient: {
...state.domain.patient,
[property]: value
}
}
}
Dynamically passing a path and updating this state can be… cumbersome. There are libraries that can help you do it such as immer, but you can possibly hack your way around with normal JS/TS.

Can't access to variable inside a function arguments call [duplicate]

This question already has answers here:
How to use a variable for a key in a JavaScript object literal?
(16 answers)
Closed 2 years ago.
case 'ADD_CHAT_MESSAGE':
const index = state.tasks.findIndex(elm => elm.userid === action.taskid)
const task = state.tasks
return update(
state, { tasks: { index: { $set: action.task } } })
I would like to use index inside update function but my IDE alerting me that index is declared nut never used.
Since index is dynamic, you must use [] with it, otherwise it will just be setting the index key
case 'ADD_CHAT_MESSAGE':
const index = state.tasks.findIndex(elm => elm.userid === action.taskid)
const task = state.tasks
return update(
state, { tasks: { [index]: { $set: action.task } } })

map() returns value pairs with object [duplicate]

This question already has answers here:
Add a property to a JavaScript object using a variable as the name? [duplicate]
(14 answers)
Closed 3 years ago.
I have object like picture below.
I want to use map() to retrieve the object like
{
"2643216":{pg:1,pt:1},
"1304681":{pg:1,pt:1}
}
Here is my code.
Object.keys(obj).map(function(x){
return {obj[x].number:{'pg':obj[x].pg,'pt':obj[x].pt}}
})
But errors may appear at the obj[x].number.
The debug errors notifies me the ignorance of the : (colon).
Is there mistake I make and any adjustment you can suggest-
or other way can retrieve the object I want?
Thank you.
this should do the job:
function groupByNumber(data) {
return Object
.keys(data)
.reduce(function(result, key) {
var value = data[key];
result[value.number] = { pt: value.pt, pg: value.pg };
return result;
}, {});
};
var data = {
'LKB_something': { number: 1, pg: 1, pt: 5 },
'LKB_something_else': { number: 2, pg: 1, pt: 5 },
'LKB_something_else_1': { number: 3, pg: 1, pt: 5 },
};
console.log('result', groupByNumber(data));
// ES-NEXT would let you be more coincise
const groupByNumber = data => Object.values(data).reduce(
(result, { number, ...rest }) => ({ ...result, [number]: rest }),
{},
);
For a dynamic key in a JavaScript object, you need square brackets to make a computed property name:
return { [obj[x].number]: { "pg": obj[x].pg, "pt": obj[x].pt }}
And your code could be simplified using Object.values and the implicit return of an arrow function, along with destructuring and shorthand property notation, like so:
Object.values(obj).map(({ number, pg, pt }) => ({ [number]: { pg, pt }}))
Note that the above returns an array of objects - if you want an object:
Object.values(obj).reduce((a, { number, pg, pt }) => ({ ...a, [number]: { pg, pt }}), {})

Updating object in array with Vuex [duplicate]

This question already has answers here:
Update data using vuex
(4 answers)
Closed 4 years ago.
How can I update an object inside an array with Vuex? I tried this, but it didn't work:
const state = {
categories: []
};
// mutations:
[mutationType.UPDATE_CATEGORY] (state, id, category) {
const record = state.categories.find(element => element.id === id);
state.categories[record] = category;
}
// actions:
updateCategory({commit}, id, category) {
categoriesApi.updateCategory(id, category).then((response) => {
commit(mutationType.UPDATE_CATEGORY, id, response);
router.push({name: 'categories'});
})
}
[mutationType.UPDATE_CATEGORY] (state, id, category) {
state.categories = [
...state.categories.filter(element => element.id !== id),
category
]
}
This works by replacing the 'categories' array with the original array without the matching element, and then concatenating the updated element to the end of the array.
One caveat to this method is that it destroys the order of the array, although in a lot of cases that won't be a problem. Just something to keep in mind.

check value is object when updating state [duplicate]

This question already has answers here:
Finding Variable Type in JavaScript
(12 answers)
Closed 5 years ago.
I am sending the following data to my reducer:
const data = {
value: { age, gender, ethnicity },
field: 'accessCode',
actionType: 'ADD_DETAILS',
};
this.props.dispatch(formHandler(data));
How can I check to see if the value prop is a single value, or an object with three values?
My action:
export function formHandler(data) {
return function(dispatch) {
// check data.value is an object with three value
if (..) {
this.props.dispatch(
showError({
type: 'SHOW_MODAL',
modalType: 'SHOW_ERROR',
})
);
} else {
dispatch({
type: data.actionType,
field: data.field,
value: data.value,
});
}
};
}
My reducer to update state:
switch (action.type) {
case ADD_LANGUAGE:
case ADD_ACCESSCODE:
case ADD_ACCESSCODE:
case ADD_DRINKS_CONCERN:
return {
...state,
[action.field]: action.value,
};
case ADD_DETAILS:
return {
...state,
...action.value,
};
Concerning the comment of how to check, this could be a start.
if (typeof(data.value) === 'object' && Object.keys(data.value).length === 3)
I'm not exactly sure how specific your needs are (does it need to be exactly 3 keys for example), but feel free to expand and I can chime in.
If you are okay using the Object prototype, you can test using this:
Object.getOwnPropertyNames(data).length
Object.getOwnPropertyNames returns an array with all property values with a length property of it's own included.

Categories