What is the best way to overwrite an object inside an array of objects?
I would like to have only one object per username, in this case in the initial arr Francis has a showMessage to true but userDetails has the same username but different value for the showMessage so I would like to overwrite this last object in the array.
Expected output:
[
{ showMessage: true, username: 'Joe' },
{ showMessage: true, username: 'Douglas' },
{ showMessage: false, username: 'Francis' }
]
Current code:
let obj = {};
let arr = [
{showMessage: true, username: "Joe"},
{showMessage: true, username: "Douglas"},
{showMessage: true, username: "Francis"}
]
const userDetails = {
showMessage: false,
username: 'Francis',
}
objJSON = userDetails
var newData = [...arr, userDetails]
console.log("newData: ",newData);
CodePudding user response:
Use Object.assign after finding in array the object which matches the username
— in order to overwrite/modify the object data with another Object of data
const arr = [
{showMessage: true, username: "Joe"},
{showMessage: true, username: "Douglas"},
{showMessage: true, username: "Francis"}
]
const userDetails = {
showMessage: false,
username: 'Francis',
};
// Update user data by username (if object is found in array):
const oldDetails = arr.find(user => user.username === userDetails.username);
oldDetails && Object.assign(oldDetails, userDetails);
console.log(arr);
CodePudding user response:
I would typically find the index with that username, if it exists, splice the new object into that position, if not, splice the new object onto the end
let arr = [
{showMessage: true, username: "Joe"},
{showMessage: true, username: "Douglas"},
{showMessage: true, username: "Francis"}
]
const userDetails = {
showMessage: false,
username: 'Francis',
}
const set = (obj) => {
const i = arr.findIndex(el => el.username === obj.username);
arr.splice(i === -1 ? arr.length : i, i === -1 ? 0 : 1, obj);
return arr;
}
var newData = set(userDetails)
console.log("newData: ",newData);
Which works both for adding a new object, and editing an existing
However, I'd generally avoid the issue entirely by using the username as a key, instead of an array:
let arr = {
Joe: {showMessage: true, username: "Joe"},
Douglas: {showMessage: true, username: "Douglas"},
Francis: {showMessage: true, username: "Francis"}
}
const userDetails = {
showMessage: false,
username: 'Francis',
}
const set = (obj) => {
arr[obj.username] = obj
}
set(userDetails)
console.log("newData: ", Object.values(arr));
CodePudding user response:
let arr = [
{ showMessage: true, username: "Joe" },
{ showMessage: true, username: "Douglas" },
{ showMessage: true, username: "Francis" },
];
const userDetails = {
showMessage: false,
username: "Francis",
};
const newData = [...arr];
for (let i = 0; i < newData.length; i ) {
if (arr[i].username == userDetails.username) {
newData[i] = userDetails;
}
}
console.log("newData: ", newData);
CodePudding user response:
Just map through the object and reassign the value with the desired one.
let obj = {};
let arr = [
{showMessage: true, username: "Joe"},
{showMessage: true, username: "Douglas"},
{showMessage: true, username: "Francis"}
]
const userDetails = {
showMessage: false,
username: 'Francis',
}
arr.map((user) => {
if(user.username === userDetails.username){
user.showMessage = userDetails.showMessage
}
})
var newData = [...arr]
console.log("newData: ",newData);
CodePudding user response:
We can separate out the match-testing from the object merging by writing a generic version that takes a predicate. Here's a version that does this in an immutable manner:
const mergeWhere = (pred) => (objs, obj) =>
objs .map (o => pred (obj, o) ? Object .assign ({}, o, obj) : o)
const updateUser = mergeWhere ((a, b) => a.username == b.username)
const arr = [{showMessage: true, username: "Joe"}, {showMessage: true, username: "Douglas"}, {showMessage: true, username: "Francis"}]
const userDetails = {showMessage: false, username: 'Francis'}
console .log (updateUser (arr, userDetails))
.as-console-wrapper {max-height: 100% !important; top: 0}
This merges our output into all matching inputs. We could do it for just the first one with something like
const mergeWhere = (pred) => (objs, obj, index = objs .findIndex (o => pred (obj, o))) =>
index == -1
? [...objs]
: [...objs .slice (0, index), Object .assign ({}, objs [index], obj) , objs .slice (index 1)]