Update nested data arrays of object (Redux) - javascript

I have an issue with updating the immutable redux and quite nested data. Here's an example of my data structure and what I want to change. If anyone could show me the pattern of accessing this update using ES6 and spread operator I would be thankful. 😀
const formCanvasInit = {
id: guid(),
fieldRow: [{
id: guid(),
fieldGroup: [
{ type: 'text', inputFocused: true }, // I want to change inputFocused value
{ type: 'text', inputFocused: false },
],
}],
// ...
};

This should do the trick, assuming the data is set up exactly as shown, with the given array indices:
const newData = {
...formCanvasInit,
fieldRow: [{
...formCanvasInit.fieldRow[0],
fieldGroup: [
{ ...formCanvasInit.fieldRow[0].fieldGroup[0], inputFocused: newValue },
...formCanvasInit.fieldRow[0].fieldGroup.slice(1, formCanvasInit.fieldRow[0].fieldGroup.length)
]
}]
};
If index of the element to be changed is to be determined dynamically, you'll need to use functionality such as filter to find and remove the array element you're updating, and then spread the corresponding subarrays by editing the structure of the call to slice.

Try using Immutability Helper
I think in your structure, like this
let news = update(formCanvasInit, {
fieldRow: [{
fieldGroup: [
{ $set: {type: "number", inputFocused: false}}
]
}]
})
I've tried it
Click Me

This is a longer solution but might help you as your redux state grows. I've also changed some of the values in the original state to make a clearer explanation.
const formCanvasInit = {
id: 'AAAAXXXX',
fieldRow: [
{
id: 1001,
fieldGroup: [
{type: 'text1', inputFocused: true}, // I want to change inputFocused value
{type: 'text2', inputFocused: false},
]
},
{
id: 1002,
fieldGroup: [
{type: 'text3', inputFocused: true},
{type: 'text4', inputFocused: true},
]
}
]
};
// the id of the field row to update
const fieldRowID = 1001;
// the value of the field type to update
const fieldTypeValue = 'text1';
const fieldRow = [...formCanvasInit.fieldRow];
// obtain the correct fieldRow object
const targetFieldRowIndex = formCanvasInit.fieldRow.findIndex(fR => fR.id === fieldRowID);
let fieldRowObj = targetFieldRowIndex && formCanvasInit.fieldRow[targetFieldRowIndex];
// obtain that fieldRow object's fieldGroup
const fieldGroup = [...fieldRowObj.fieldGroup];
// obtain the correct object in fieldGroup
const fieldIndex = fieldGroup.findIndex(fG => fG.type === fieldTypeValue);
const fieldToChange = fieldIndex && fieldGroup[fieldIndex];
// replace the old object in selected fieldGroup with the updated one
fieldGroup.splice(fieldIndex, 1, {...fieldToChange, inputFocused: false});
// update the target fieldRow object
fieldRowObj = {...fieldRowObj, fieldGroup};
// replace the old fieldGroup in selected fieldRow with the updated one
fieldRow.splice(targetFieldRowIndex, 1, fieldRowObj);
// create the new formCanvasInit state
const newFormCanvasInit = {...formCanvasInit, fieldRow};

Related

Javascript: Spread array of an object in an object and change properties inside it only

I have a scenario where I want to change properties of object in an array. That array is wrapped inside another object.
const defaultData = {
title: "Title",
subtitle: "Subtitle",
books: [
{
bookId: "1",
imageSrc:
"any.png",
name: "Issue",
userOwnsData: true,
panelsCollected: 0,
totalPanels: 123,
link: "https://google.com",
},
],
bgColor: "black",
};
When I spread it like this:
{...defaultData, ...defaultData.books[0], panelsCollected:123} //previously it was 0
then it adds another extra object to parent object but not update it inside first index of books array
How can I just change that panelsCollected property without disturbing whole structure as we are using typescript.
Edit:
We can change it directly accessing the property too as we know index but that comes with a side effect of manipulating original dataset also which we should avoid and only copy needs to be updated.
Thanks
When spreading an object with nested properties with the intention of updating specific properties, think of it in two steps:
Spread the original object to copy it (...)
Redefine the new property values after the spread object
In your example we are doing the following:
Duplicating defaultData and assigning an updated books property (to be defined in the next step)
Duplicating the first book (defaultData.books[0]) and assigning an updated panelsCollected property to it. Then overwriting the existing books property with this updated array item
The result is as follows:
const defaultData = {
title: "Title",
subtitle: "Subtitle",
books: [
{
bookId: "1",
imageSrc:
"any.png",
name: "Issue",
userOwnsData: true,
panelsCollected: 0,
totalPanels: 123,
link: "https://google.com",
},
],
bgColor: "black",
};
const newBook = {
...defaultData,
books: [
{
...defaultData.books[0],
panelsCollected: 123
}
]
}
console.log(newBook)
/*
{
title: "Title",
subtitle: "Subtitle",
books: [
{
bookId: "1",
imageSrc:
"any.png",
name: "Issue",
userOwnsData: true,
panelsCollected: 123,
totalPanels: 123,
link: "https://google.com",
},
],
bgColor: "black",
};
*/
If for example the books property was 1000 items long, you would instead use have to find the specific book in your array using an array method (e.g. find / findIndex) and update it, e.g.
const bookToUpdateIndex = defaultData.books.findIndex(book => book.bookId === '1')
const updatedBooks = [...defaultData.books]
updatedBooks[bookToUpdateIndex] = {
...updatedBooks[bookToUpdateIndex],
panelsCollected: 123
}
const newBook = {
...defaultData,
books: updatedBooks
}
I think it is creating another parent object because you are using the spread twice. I tried to do 2 console logs. Please let me know if this is the result you are looking for.
console.log({...defaultData['books'][0]['panelsCollected'] = 10})
console.log(defaultData);
Instead of using find and the spread syntax an alternative approach (but not necessarily the most performant) might be to copy the object by stringifying it, and then reparsing that string. And then you can just update the object at the index you need.
const defaultData={title:"Title",subtitle:"Subtitle",books:[{bookId:"1",imageSrc:"any.png",name:"Issue",userOwnsData:!0,panelsCollected:0,totalPanels:123,link:"https://google.com"}],bgColor:"black"};
const copy = JSON.parse(JSON.stringify(defaultData));
copy.books[0].panelsCollected = 123;
console.log(defaultData);
console.log(copy);

Javascript filter parent array based on child containing value

I am trying to filter the parent array products based on the selected value which should be contained as the child. For example in my case I was trying to get all the product objects as an array which contained the string "iphone". It is not working for me and I can't seem to locate my error. Please may someone help.
What I have tried:
const selected = 'iphone'
const products = [
{
id: "4irnflpd0",
productItem: [ "iphone", "ipad", "kindle"],
},
{
id: "glrscb1m3s9k",
productItem: ["airpods","iphone",],
},
{
id: "uumkugk3jxof",
productItem: ["macbook","cable"]
},
]
var filtered = products.map(o=>{
o = Object.assign({},o); //Clone the object. So any changes will not affect the original array.
o.productItem.map(p=>{ //Use map to loop thru the products
p = p.filter(v=>v === selected); //Filter the products which include selected
});
return o;
})
Expected array output:
const products = [
{
id: "4irnflpd0",
productItem: [ "iphone", "ipad", "kindle"],
},
{
id: "glrscb1m3s9k",
productItem: ["airpods","iphone",],
},
]
Just a simple filter() method should work for us in this case. T further simplify, we can also use object restructuring, so instead of writing product.productItem.includes(selected), we'll only need to write productItem.includes(selected).
All we have to do is filter the source array by which items include the selected value:
const selected = 'iphone';
const products = [
{ id: "4irnflpd0", productItem: ["iphone", "ipad", "kindle"] },
{ id: "glrscb1m3s9k", productItem: ["airpods", "iphone", ] },
{ id: "uumkugk3jxof", productItem: ["macbook", "cable"] },
];
const filtered = products.filter(({productItem}) => productItem.includes(selected));
console.log(filtered);
If you'd prefer not to use Object destructuring, just swap that filter line for this more traditional one:
products.filter(p => p.productItem.includes(selected))
If you're not sure that every single item in your array will have the productItem key, then you should use optional chaining to prevent an error being thrown. This is as simple as adding ? before after property name. Here it is all put together:
products.filter(p => p.productItem?.includes(selected))
First of all no need to make a copy since with map function you allocated the result to new variable without changing the new array
So you need to do this
const filtered = products.map(p=>{
return p.productItem.includes(selected)
})
You can use the filter() methods on products array and find if the selected item is available in the productItems
const selected = 'iphone'
const products = [
{ id: "4irnflpd0", productItem: [ "iphone", "ipad", "kindle"] },
{ id: "glrscb1m3s9k", productItem: ["airpods","iPhone",] },
{id: "uumkugk3jxof", productItem: ["macbook","cable"] }
]
var filtered = products.filter(product =>
product.productItem?.includes(selected));
console.log(filtered);

Update property value in nested array (redux state)

How do you update a certain nested property in redux state?
Let's say I only want to update the "value" property in the object below. I know you shouldn't deep copy the previous state but how do i only change the property of an object in an array in an object of an array?
Thanks in advance!
market {
shops: [
{
name: 'abc',
items: [
{
name: 'item1',
value: 40,
id: '234rfds32'
},
{}
]
},
{},
{}
]
}
Something like the following:
state = {
...state,
shops: [
...state.shops,
shops[index].items = [
...shops[index].items,
]
]
};
Something like this would work. (code looks ugly, didn't test though)
var shop = state.shops[index];
var items = [...shop.items];
items[<index>].value = 'your value';
shop.items = items;
var shops = [...state.shops];
shops[index] = shop;
state = {
...state,
shops
};

json object from javascript nested array

I'm using a nested array with the following structure:
arr[0]["id"] = "example0";
arr[0]["name"] = "name0";
arr[1]["id"] = "example1";
arr[1]["name"] = "name1";
arr[2]["id"] = "example2";
arr[2]["name"] = "name2";
now I'm trying to get a nested Json Object from this array
arr{
{
id: example0,
name: name00,
},
{
id: example1,
name: name01,
},
{
id: example2,
name: name02,
}
}
I tought it would work with JSON.stringify(arr); but it doesen't :(
I would be really happy for a solution.
Thank you!
If you are starting out with an array that looks like this, where each subarray's first element is the id and the second element is the name:
const array = [["example0", "name00"], ["example1", "name01"], ["example2", "name02"]]
You first need to map it to an array of Objects.
const arrayOfObjects = array.map((el) => ({
id: el[0],
name: el[1]
}))
Then you can call JSON.stringify(arrayOfObjects) to get the JSON.
You need to make a valid array:
arr = [
{
id: 'example0',
name: 'name00',
},
{
id: 'example1',
name: 'name01',
},
{
id: 'example2',
name: 'name02',
}
];
console.log(JSON.stringify(arr));
Note that I am assigning the array to a variable here. Also, I use [] to create an array where your original code had {}.

JS – How to build a dynamic nested object of arrays with objects etc. from string

This is a nice evening project, but actually i'm stuck with some headache.
All I need is a function like this example:
result = set("itemCategories[0].items[0].name", "Test")
which should return:
{ itemCategories: [
{
items: [ {name: "Test"} ]
}
}]
...and in case of the given attribute "itemCategories[1].items[2].name" this result:
{ itemCategories: [
null,
{
items: [
null,
null,
{name: "Test"}
]
}
}]
Use lodash#set:
result = lodash.set({}, "itemCategories[0].items[0].name", "Test")
If you are asking about the vanilla JavaScript Set method then you could do this.
/* this is what you are trying to get.
{ itemCategories: [
{
items: [ {name: "Test"} ]
}
}]
*/
var mySet = new Set(); // your set object.
Create your data (number, text, string, object, array, null).
ver data1 = 365;
ver data2 = 'Dragonfly';
ver data3 = {name: 'Bobby', age: 20000, job: 'dj'};
Then you just add to that set using its add method.
mySet.add(data1);
mySet.add(data2);
mySet.add(data3);
So to get what you are looking for you would write this.
var itms = {items: [{name: 'test'}]};
mySet.add(itms);
The good thing about set is that is like an array. So you can use forEach.
mySet.forEach( function(val){
console.log(val); // gets all your data.
});
You can even check if a value is in your data using the has method.
mySet.has(365); // true
mySet.has(36500000); as false
JavaScript Set

Categories

Resources