const array = [
{
id: "1",
children: [],
messages:[1, 'Text'],
entry: "Father",
},
{
id: "2",
entry: "Mother",
children: [
{entry: "John Jr"},
{entry: "Steven Jr"},
{entry: "Tim Jr"},
],
messages:[2, 'Text'],
},
{
id: "3",
entry: "Son",
children: [
{entry: "XXX Jr"},
{entry: "Steven Jr"},
{entry: "Tim Jr"}
],
messages:[3, 'Text'],
},
]
So what I want here is, when I do the search "Tim". I want the output to be
Case 1: When I search for Tim, I should get the object with id: 2 and id: 3 because Tim is an entry matching in both the objects. so I want to return the entire id: 2 and 3 object in the same order.
{
id: "2",
entry: "Mother",
children: [
{entry: "John Jr"},
{entry: "Steven Jr"},
{entry: "Tim Jr"},
],
messages:[2, 'Text'],
},
{
id: "3",
entry: "Son",
children: [
{entry: "XXX Jr"},
{entry: "Steven Jr"},
{entry: "Tim Jr"}
],
messages:[3, 'Text'],
}
Case 2: When I search for John, I should get second object as
{
id: "2",
entry: "Mother",
children: [
{entry: "John Jr"},
],
messages:[2, 'Text'],
}
Case 3: When I search for Steven, I should get id:2 and id:3 as
id: "2",
entry: "Mother",
children: [
{entry: "John Jr"},
{entry: "Steven Jr"},
],
messages:[2, 'Text'],
},
{
id: "3",
entry: "Son",
children: [
{entry: "XXX Jr"},
{entry: "Steven Jr"},
],
messages:[3, 'Text'],
}
I used .filter() to filter the top level but this isn't checking the children.
array.filter((item) => item.entry.toUpperCase().includes(text.toUpperCase()));
Any help would be greatly appreciated as I'm totally lost with forEach here. Thanks in advance
CodePudding user response:
you can use Array.Filter ,
Array.some and splice the children array with index of the search entry
object
const array = [{
id: "1",
children: [],
messages: [1, 'Text'],
entry: "Father",
},
{
id: "2",
entry: "Mother",
children: [{
entry: "John Jr"
},
{
entry: "Steven Jr"
},
{
entry: "Tim Jr"
},
],
messages: [2, 'Text'],
},
{
id: "3",
entry: "Son",
children: [{
entry: "XXX Jr"
},
{
entry: "Steven Jr"
},
{
entry: "Tim Jr"
}
],
messages: [3, 'Text'],
},
];
let searchText = 'John';
let result = array.filter(el => {
let i;
let found = el.children.some((e, j) => {
i = j;
return e.entry.toLowerCase().indexOf(searchText.toLowerCase()) >= 0;
});
if (found)
el.children = el.children.splice(0, i 1);
return found;
});
console.log(result);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
const data=[{id:"1",children:[],messages:[1,"Text"],entry:"Father"},{id:"2",entry:"Mother",children:[{entry:"John Jr", children: [{entry: 'Bob', children: [{entry: 'Marvin'},{entry: 'Summer', children: [{entry: 'Batman'}, {entry: 'Robin'}]}]},{entry: 'Dave', children: [{entry: 'Sue'}, {entry: 'Sam'}]}]},{entry:"Steven Jr"},{entry:"Tim Jr"}],messages:[2,"Text"]},{id:"3",entry:"Son",children:[{entry:"XXX Jr", children: [{entry: 'Batman'}]},{entry:"Steven Jr"},{entry:"Tim Jr"}],messages:[3,"Text"]}];
function recurseChildren(children) {
const arr = [];
function loop(children) {
for (const entry of children) {
arr.push(entry.entry);
if (entry.children) {
loop(entry.children);
}
}
}
loop(children);
return arr;
}
function finder(data, name) {
// `filter` over the array
return data.filter(obj => {
// Recurse over the children array of all entries
// to compile a list of names
const names = recurseChildren(obj.children);
// For each object check to see if
// at least one of the entries in children
// includes the name
return names.some(entry => {
return entry.includes(name);
});
});
}
console.log(finder(data, 'Tim'));
console.log(finder(data, 'John'));
console.log(finder(data, 'Steven'));
console.log(finder(data, 'Batman'));
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>