How to remove child object from parent object list javascript - javascript

<script> var itemsTemp= [
{ id: 0, text: 'Andy' },
{
id: 1, text: 'Harry',
children: [
{ id: 2, text: 'David' }
]
},
{ id: 3, text: 'Lisa' },
{ id: 4, text: 'Mona' },
{ id: 5, text: 'Ron' },
{ id: 6, text: 'Joe' }
];
var items = itemsTemp;
var filtered = items.filter(function(item) {
return item.id !== 3;
});
console.log(filtered);
</script>
in this way, I can only remove the parent but how can I delete the child object? please help me to fix this

Since you want to filter children, you can use .reduce() to perform a mapping and filtering of your array. When you reach an object which has a children property, you can recursively call your function to then perform the mapping/filtering on the child array .reduce() array like so:
const items = [{ id: 0, text: 'Andy' }, { id: 1, text: 'Harry', children: [{ id: 2, text: 'David' }] }, { id: 3, text: 'Lisa' }, { id: 4, text: 'Mona' }, { id: 5, text: 'Ron' }, { id: 6, text: 'Joe' } ];
const filterItems = (items, fn) => items.reduce((acc, item) => {
if(item.children)
return [...acc, ...filterItems(item.children, fn)];
else if(fn(item))
return [...acc, item];
return acc;
}, []);
const filtered = filterItems(items, item => item.id !== 2);
console.log(filtered);
If you don't want to remove the item from the parent list, and only from the child list, then you push an update object instead:
const items = [{ id: 0, text: 'Andy' }, { id: 1, text: 'Harry', children: [{ id: 2, text: 'David' }] }, { id: 3, text: 'Lisa' }, { id: 4, text: 'Mona' }, { id: 5, text: 'Ron' }, { id: 6, text: 'Joe' } ];
const toRemoveId = 2;
const filterItems = (items, fn) => items.reduce((acc, item) => {
if(item.children)
return [...acc, {...item, children: filterItems(item.children, fn)}];
else if(fn(item))
return [...acc, item];
return acc;
}, []);
const filtered = filterItems(items, item => item.id !== 2);
console.log(filtered);
This will work for arbitrary object depths.

I just wrote the filterById function I think it works for your case
var itemsTemp = [
{ id: 0, text: "Andy" },
{
id: 1,
text: "Harry",
children: [{ id: 2, text: "David" }],
},
{ id: 3, text: "Lisa" },
{ id: 4, text: "Mona" },
{ id: 5, text: "Ron" },
{ id: 6, text: "Joe" },
];
var items = itemsTemp;
const filterById = (items, id) => {
return items.reduce((accumulator, currentValue) => {
if(currentValue.children){
const newCurrentValue = filterById(currentValue.children, id)
currentValue = {...currentValue, children: newCurrentValue}
}
if(currentValue.id !== id){
return [...accumulator, currentValue]
}
return accumulator
},[])
}
console.log(filterById(itemsTemp,2));
console.log(itemsTemp)

I think you can do like this.
var itemsTemp= [
{ id: 0, text: 'Andy' },
{
id: 1, text: 'Harry',
children: [
{ id: 2, text: 'David' }
]
},
{ id: 3, text: 'Lisa' },
{ id: 4, text: 'Mona' },
{ id: 5, text: 'Ron' },
{ id: 6, text: 'Joe' }
];
var items = itemsTemp;
var filtered = items.filter(function(item) {
childrens=item.children;
if(childrens)
{
filteredchildren = childrens.filter(children=>children.id!==2);
item.children=filteredchildren;
}
return item.id !== 2;
});
console.log(filtered);

Related

How to change value in array with objects in JS

I have an array and want to change name in object { id: 4, name: 'name4' } to 'name6'
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
]
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' }
]
},
I try in this way but it isn't working
const name = 'name4';
const result = example?.forEach((group) =>
group.items.forEach((item) =>
if (item.name === name) {
return item.name === 'name6';
}
return null;
})
);
The for...of statement is my recommendation for readability and loop optimisation.
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' },
],
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' },
],
},
];
const oldName = 'name4';
const newName = 'name6';
for (const group of example) {
for (const item of group.items) {
if (item.name === oldName) {
item.name === newName;
break
}
}
}
You could even go a step further and terminate the outer loop with a label if you only need to change the name in a single group.
outerLoop: for (const group of example) {
for (const item of group.items) {
if (item.name === oldName) {
item.name === newName;
break outerLoop;
}
}
}
Hope this helps.
You could either change the value by simply assigning a new value.
example[1].items[0].name = 'name6'
But you can also iterate through all items and search for the name you want to change. I created a function that goes through an array and loops over its nested items arrays searching for any given name (targetName) and replacing it with a new one (newName):
function changeName(array, targetName, newName) {
// Loop through the elements of array
array.forEach((element) => {
// Check each item: change the name if it matches the target
element.items.forEach((item) => {
if (item.name === targetName) item.name = newName;
});
});
}
// This function will check example array and change
// every name that has a value 'name4' into 'name6'
changeName(example, "name4", "name6");
forEach doesn't return any value.
Instead of return item.name === 'name6' you can simply set new value to item.name.
Why not like this?
const example = [{
id: '1234',
desc: 'sample1',
items: [{
id: 1,
name: 'name1'
},
{
id: 2,
name: 'testItem2'
}
]
},
{
id: '3456',
desc: 'sample2',
items: [{
id: 4,
name: 'name4'
},
{
id: 5,
name: 'testItem5'
}
]
},
]
example[1].items[0].name = 'name6'
console.log(example)

JavaScript modifying an object inside the array

I am having a problem trying to modify the name of a nested object using map function and to return the modified object.
I was trying the approach with double forEach loop but I am also failing with that.
const myObject = [{
id: 1,
childrenList: [{
id: 1,
name: 'foo',
},
{
id: 2,
name: 'foo',
},
],
},
{
id: 2,
childrenList: [{
id: 1,
name: 'foo',
},
{
id: 2,
name: 'foo',
},
],
},
];
const alteredObject = myObject.map((thisChild) => {
if (thisChild.id === 1) {
thisChild.childrenList.map((item) => {
if (item.id === 1) {
return {
...item,
name: 'bar',
};
}
return item;
});
}
return thisChild;
});
console.log(alteredObject);
//trying to get:
alteredObject = [
{
id: 1,
childrenList: [
{
id: 1,
name: 'bar',
},
{
id: 2,
name: 'foo',
},
],
},
{
id: 2,
childrenList: [
{
id: 1,
name: 'foo',
},
{
id: 2,
name: 'foo',
},
],
},
];
This is the first time I am trying to modify a nested object. Normally with an array of objects, I am not having any issue so I am not sure what I am doing wrong
You only need to update the children with your map and it will work. Like this:
const myObject = [
{
id: 1,
childrenList: [
{
id: 1,
name: "foo"
},
{
id: 2,
name: "foo"
}
]
},
{
id: 2,
childrenList: [
{
id: 1,
name: "foo"
},
{
id: 2,
name: "foo"
}
]
}
];
const alteredObject = myObject.map((thisChild) => {
if (thisChild.id === 1) {
thisChild.childrenList = thisChild.childrenList.map((item) => {
if (item.id === 1) {
return {
...item,
name: "bar"
};
}
return item;
});
}
return thisChild;
});
console.log(alteredObject);
And if you want to do it with forEach:
const myObject = [
{
id: 1,
childrenList: [
{
id: 1,
name: "foo"
},
{
id: 2,
name: "foo"
}
]
},
{
id: 2,
childrenList: [
{
id: 1,
name: "foo"
},
{
id: 2,
name: "foo"
}
]
}
];
const alteredObject = myObject.map((thisChild) => {
if (thisChild.id === 1) {
thisChild.childrenList.forEach((item) => {
if (item.id === 1) {
item.name = 'bar';
}
return item;
});
}
return thisChild;
});
console.log(alteredObject);
If you can modify your object then you can do it with two forEach:
const myObject = [
{
id: 1,
childrenList: [
{
id: 1,
name: "foo"
},
{
id: 2,
name: "foo"
}
]
},
{
id: 2,
childrenList: [
{
id: 1,
name: "foo"
},
{
id: 2,
name: "foo"
}
]
}
];
myObject.forEach((thisChild) => {
if (thisChild.id === 1) {
thisChild.childrenList.forEach((item) => {
if (item.id === 1) {
item.name = 'bar';
}
return item;
});
}
});
console.log(myObject);
As you already know, Array.prototype.map() returns a new Array containing the modified version.
In your first map function myObject.map(), you aren't saving the second map function modified result as the childrenList content.
therefore no changes would be stored in the first map function and the result would have no changes.
const alteredObject = myObject.map((thisChild) => {
if (thisChild.id === 1) {
// Here you should save the result of this
// Array.prototype.map() Function as the new 'thisChild.childrenList'
thisChild.childrenList = thisChild.childrenList.map((item) => {
// ...
});
}
return thisChild;
});
const myObject = [{
id: 1,
childrenList: [{
id: 1,
name: 'foo',
},
{
id: 2,
name: 'foo',
},
],
},
{
id: 2,
childrenList: [{
id: 1,
name: 'foo',
},
{
id: 2,
name: 'foo',
},
],
},
];
const alteredObject = myObject.map((thisChild) => {
if (thisChild.id === 1) {
thisChild.childrenList = thisChild.childrenList.map((item) => {
if (item.id === 1) {
return {
...item,
name: 'bar',
};
}
return item;
});
}
return thisChild;
});
console.log(alteredObject);
You can use this code :
const myObject = [
{
id: 1,
childrenList: [
{ id: 1, name: 'foo', },
{ id: 2, name: 'foo', },
],
},
{
id: 2,
childrenList: [
{ id: 1, name: 'foo', },
{ id: 2, name: 'foo', },
],
},
];
let result = myObject.map(
el => el.id === 1 ?
{...el, childrenList: el.childrenList.map(child => child.id === 1 ? {...child, name: 'bar'} : child)}
: el
);
console.log(result);
This can be done with a couple of map calls, we'll alter the name value if the firstChild id is 1 and the leaf object id is also 1:
const myObject = [ { id: 1, childrenList: [ { id: 1, name: 'foo', }, { id: 2, name: 'foo', }, ], }, { id: 2, childrenList: [ { id: 1, name: 'foo', }, { id: 2, name: 'foo', }, ], }, ];
const alteredObject = myObject.map((thisChild) => {
return { ...thisChild, childrenList: thisChild.childrenList.map(({id, name}) => {
return { id, name: (thisChild.id === 1 && id === 1) ? 'bar': name };
})}
});
console.log(alteredObject)
.as-console-wrapper { max-height: 100% !important; }
The array map method creates a new array (mdn), so the parent object alteredObject still has the childrenList key pointing to the original array.
To solve this, you can add assignment of the new array to the key:
thisChild.childrenList = thisChild.childrenList.map(...)
This way, the key will point to the newly created array
You're missing a return; you have to return the modified thisChild as {...thisChild, childrenList:modifiedChildrenList}
const myObject = [{ id: 1, childrenList: [{ id: 1, name: 'foo', }, { id: 2, name: 'foo', }, ], }, { id: 2, childrenList: [{ id: 1, name: 'foo', }, { id: 2, name: 'foo', }, ], }, ];
const alteredObject = myObject.map((thisChild) => {
if (thisChild.id === 1) {
return {...thisChild,childrenList:thisChild.childrenList.map((item) => {
if (item.id === 1) {
return {
...item,
name: 'bar',
};
}
return item;
})
}
}
return thisChild;
});
console.log(alteredObject);

Need change an array to add a comma at the end of each 'text', but a dot in the end of last 'text' in object

const arr = [
{ id: 1, text: "123" },
{ id: 2, text: "456" },
{ id: 3, text: "789" },
];
For example now its looks like that ^^^, but need to make it smth like that:
const arr = [
{ id: 1, text: "123," },
{ id: 2, text: "456," },
{ id: 3, text: "789." },
];
How can i do it?
Here you go:
const arr = [{
id: 1,
text: "123"
},
{
id: 2,
text: "456"
},
{
id: 3,
text: "789"
},
]
const newArr = arr.map(({
id,
text
}, idx) => ({
id,
text: `${text}${idx < arr.length -1 ? "," : "."}`
}))
console.log(newArr)

Better way to find data across multiple arrays

getComponentById: (state) => (componentId) => {
return state.articles
.filter(article => Object.keys(article).some(key => {
return ['maps', 'charts', 'tables'].includes(key);
}))
.reduce((acc, article) => {
acc = article.components?.find(c => c.id == componentId);
if (acc) return acc;
acc = article.maps?.find(c => c.id == componentId);
if (acc) return acc;
acc = article.charts?.find(c => c.id == componentId);
if (acc) return acc;
acc = article.tables?.find(c => c.id == componentId);
if (acc) return acc;
})
}
Wonder if there's a better way to rewrite this because the list of components might grow so it feels wrong to just keep adding the lines.
If the id is unique can you just look into every key on every article?
If my guess at your data structure is close you should be able to do something like this
let articles = [
{
maps: [{ id: 1, name: 'map1' }, { id: 2, name: 'map2' }],
charts: [{ id: 3, name: 'charts1' }, { id: 4, name: 'charts2' }],
tables: [{ id: 5, name: 'tables1' }, { id: 6, name: 'tables2' }]
},
{
maps: [{ id: 7, name: 'map3' }, { id: 8, name: 'map4' }],
charts: [{ id: 9, name: 'charts3' }, { id: 10, name: 'charts4' }],
tables: [{ id: 11, name: 'tables3' }, { id: 12, name: 'tables4' }]
}
]
let getComponentById = (componentId) => {
let result = null;
articles.forEach(article => {
Object.keys(article).forEach(key => {
let component = article[key].find(x=> x.id == componentId);
if(component) {
result = component;
}
});
});
return result;
}
console.log(getComponentById(3));
console.log(getComponentById(12));
Credit to #IrKenInvader's answer, I copy data from him.
I use for loop because once you find a component, you can early return and no need to check the rest of the data.
let state = {
articles: [
{
maps: [
{ id: 1, name: "map1" },
{ id: 2, name: "map2" },
],
charts: [
{ id: 3, name: "charts1" },
{ id: 4, name: "charts2" },
],
tables: [
{ id: 5, name: "tables1" },
{ id: 6, name: "tables2" },
],
},
{
maps: [
{ id: 7, name: "map3" },
{ id: 8, name: "map4" },
],
charts: [
{ id: 9, name: "charts3" },
{ id: 10, name: "charts4" },
],
tables: [
{ id: 11, name: "tables3" },
{ id: 12, name: "tables4" },
],
},
],
};
const getComponentById = state => componentId => {
for (let i = 0; i < state.articles.length; i++) {
const filteredKey = Object.keys(state.articles[i]).filter(key =>
["maps", "charts", "tables"].includes(key)
);
for (let j = 0; j < filteredKey.length; j++) {
const foundComponent = state.articles[i][filteredKey[j]].find(
a => a.id == componentId
);
if (foundComponent) return foundComponent;
}
}
return null;
};
const output = getComponentById(state)(12);
console.log(output);

Build Object Recursive

I have a Object which looks like the following obj.
var obj = [
{ id: 1, name: "animals" },
{ id: 2, name: "animals_cat" },
{ id: 3, name: "animals_dog" },
{ id: 4, name: "animals_weazle" },
{ id: 5, name: "animals_weazle_sand shadow weazle" },
{ id: 11, name: "fruits" },
{ id: 32, name: "fruits_banana" },
{ id: 10, name: "threes" },
{ id: 15, name: "cars" }
];
The Object should be converted into the following scheme:
var items = [
{ id: 11, name: "fruits", items: [
{ id: 32, name: "banana" }
]},
{ id: 10, name: "threes" },
{ id: 1, name: "animals", items: [
{ id: 2, name: "cat" },
{ id: 3, name: "dog" },
{ id: 4, name: "weazle", items: [
{ id: 5, name: "sand shadow weazle" }
]}
]},
{ id: 15, name: "cars" }
];
I tried a lot but unfortunately without any success. I did $.each on obj, did a split('_') on it and pushed it to items. But how can I do it for unlimited depth and push it into the right category?
I'm happy for any help.
Maybe this helps.
It works with Array.prototype.forEach for processing obj, Array.prototype.reduce for getting the right branch and Array.prototype.some for the right array element for inserting the new object.
This proposal works for sorted and consistent data.
var obj = [
{ id: 1, name: "animals" },
{ id: 2, name: "animals_cat" },
{ id: 3, name: "animals_dog" },
{ id: 4, name: "animals_weazle" },
{ id: 5, name: "animals_weazle_sand shadow weazle" },
{ id: 11, name: "fruits" },
{ id: 32, name: "fruits_banana" },
{ id: 10, name: "threes" },
{ id: 15, name: "cars" }
],
tree = [];
obj.forEach(function (a) {
var path = a.name.split('_'),
o = {};
o.id = a.id;
path.reduce(function (r, b) {
o.name = b;
r.some(function (c) {
if (c.name === b) {
c.items = c.items || [];
r = c.items;
return true;
}
});
return r;
}, tree).push(o);
});
document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');
Update: Version for independent order of items.
var obj = [
{ id: 5, name: "animals_weazle_sand shadow weazle" },
{ id: 32, name: "fruits_banana" },
{ id: 1, name: "animals" },
{ id: 2, name: "animals_cat" },
{ id: 3, name: "animals_dog" },
{ id: 4, name: "animals_weazle" },
{ id: 11, name: "fruits" },
{ id: 10, name: "threes" },
{ id: 15, name: "cars" },
{ id: 999, name: "music_pop_disco_euro"}
],
tree = [];
obj.forEach(function (item) {
var path = item.name.split('_'),
o = tree;
path.forEach(function (a, i) {
var oo = { name: a, items: [] },
last = path.length - 1 === i,
found = o.some(function (b) {
if (b.name === a) {
if (last) {
b.id = item.id;
return true;
}
b.items = b.items || [];
o = b.items;
return true;
}
});
if (!found) {
if (last) {
o.push({ id: item.id, name: a });
} else {
o.push(oo);
o = oo.items;
}
}
});
});
document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');

Categories