I'm trying to map through object values and add text if the key is right on JavaScript. Here is our object:
{
"id": "n27",
"name": "Thomas More",
"className": "level-1",
"children": [
{
"id": "n1",
"name": "Rousseau",
"className": "level-2",
"children": [
{
"id": "n2",
"name": "Machiavelli",
"className": "level-3",
"children": [
{
"id": "n9",
"name": "Edison, Thomas",
"className": "level-4"
}
]
}
]
},
{
"id": "n3",
"name": "Einstein",
"className": "level-2",
"children": [
{
"id": "n10",
"name": "Arf, Cahit",
"className": "level-3",
"children": [
{
"id": "n15",
"name": "Rawls, John",
"className": "level-4"
}
]
},
{
"id": "n12",
"name": "Smith, Adam",
"className": "level-3",
"children": [
{
"id": "n11",
"name": "Kant, Immanuel",
"className": "level-4"
}
]
}
]
},
{
"id": "n60",
"name": "Turing, Alan",
"className": "level-2"
}
]
}
I want to add " YES" to their className's. So new object should look like this:
{
"id": "n27",
"name": "Thomas More",
"className": "level-1 YES",
"children": [
{
"id": "n1",
"name": "Rousseau",
"className": "level-2 YES",
"children": [
{
"id": "n2",
"name": "Machiavelli",
"className": "level-3 YES",
"children": [
{
"id": "n9",
"name": "Edison, Thomas",
"className": "level-4 YES"
}
]
}
]
},
{
"id": "n3",
"name": "Einstein",
"className": "level-2 YES",
"children": [
{
"id": "n10",
"name": "Arf, Cahit",
"className": "level-3 YES",
"children": [
{
"id": "n15",
"name": "Rawls, John",
"className": "level-4 YES"
}
]
},
{
"id": "n12",
"name": "Smith, Adam",
"className": "level-3 YES",
"children": [
{
"id": "n11",
"name": "Kant, Immanuel",
"className": "level-4 YES"
}
]
}
]
},
{
"id": "n60",
"name": "Turing, Alan",
"className": "level-2 YES"
}
]
}
I have tried this, but it adds to all of the keys:
const addToClassName = (datasource, fn) => {
return Object.fromEntries(Object
.entries(datasource, fn)
.map(([k, v]) => [k, v && v.children != undefined && v.children.length > 0 ? addToClassName(v.children, fn) : fn(v)])
);
}
let res = addToClassName(obj, v => v + ' YEP');
How can I do it?
You don't need to use Object.fromEntries(), instead, you make your function return a new object, with a transformed className based on the return value of fn. You can then set the children: key on the object to be a mapped version of all the objects inside of the children array. When mapping, you can pass each child into the recursive call to your addToClassName() function. You can add the children key conditionally to the output object but checking if it exists (with children &&) and then by spreading the result using the spread syntax ...:
const data = { "id": "n27", "name": "Thomas More", "className": "level-1", "children": [ { "id": "n1", "name": "Rousseau", "className": "level-2", "children": [ { "id": "n2", "name": "Machiavelli", "className": "level-3", "children": [ { "id": "n9", "name": "Edison, Thomas", "className": "level-4" } ] } ] }, { "id": "n3", "name": "Einstein", "className": "level-2", "children": [ { "id": "n10", "name": "Arf, Cahit", "className": "level-3", "children": [ { "id": "n15", "name": "Rawls, John", "className": "level-4" } ] }, { "id": "n12", "name": "Smith, Adam", "className": "level-3", "children": [ { "id": "n11", "name": "Kant, Immanuel", "className": "level-4" } ] } ] }, { "id": "n60", "name": "Turing, Alan", "className": "level-2" } ] };
const addToClassName = (obj, fn) => ({
...obj,
className: fn(obj.className),
...(obj.children && {children: obj.children.map(child => addToClassName(child, fn))})
});
console.log(addToClassName(data, v => v + " YES"));
If you can change the current obj object then you can achieve this using recursion as
function addClass(obj) {
obj.className += " YES";
obj.children && obj.children.forEach(addClass);
}
const obj = {
id: "n27",
name: "Thomas More",
className: "level-1",
children: [
{
id: "n1",
name: "Rousseau",
className: "level-2",
children: [
{
id: "n2",
name: "Machiavelli",
className: "level-3",
children: [
{
id: "n9",
name: "Edison, Thomas",
className: "level-4",
},
],
},
],
},
{
id: "n3",
name: "Einstein",
className: "level-2",
children: [
{
id: "n10",
name: "Arf, Cahit",
className: "level-3",
children: [
{
id: "n15",
name: "Rawls, John",
className: "level-4",
},
],
},
{
id: "n12",
name: "Smith, Adam",
className: "level-3",
children: [
{
id: "n11",
name: "Kant, Immanuel",
className: "level-4",
},
],
},
],
},
{
id: "n60",
name: "Turing, Alan",
className: "level-2",
},
],
};
function addClass(obj) {
obj.className += " YES";
obj.children && obj.children.forEach(addClass);
}
addClass(obj);
console.log(obj);
You can use lodash, if don't mind.
const _ = require('lodash');
const data = { "id": "n27", "name": "Thomas More", "className": "level-1", "children": [ { "id": "n1", "name": "Rousseau", "className": "level-2", "children": [ { "id": "n2", "name": "Machiavelli", "className": "level-3", "children": [ { "id": "n9", "name": "Edison, Thomas", "className": "level-4" } ] } ] }, { "id": "n3", "name": "Einstein", "className": "level-2", "children": [ { "id": "n10", "name": "Arf, Cahit", "className": "level-3", "children": [ { "id": "n15", "name": "Rawls, John", "className": "level-4" } ] }, { "id": "n12", "name": "Smith, Adam", "className": "level-3", "children": [ { "id": "n11", "name": "Kant, Immanuel", "className": "level-4" } ] } ] }, { "id": "n60", "name": "Turing, Alan", "className": "level-2" } ] };
const newData= _.cloneDeepWith(data, (val, key) => (
(key === 'className') ? `${val} YES` : _.noop()
));
console.log(newData);
// {
// id: 'n27',
// name: 'Thomas More',
// className: 'level-1 YES',
// ...
// }
Related
I want to iterate the tree and need to get the id of all the nodes which has the children in string array. while looping it is just returning me the record but doesn't extract the name of the node.
e.g const result = ['root', 'USER', 'ROLE', 'DASHBOARD', 'BRAND', 'COMPANY'];
{
"id": "root",
"name": "Roles and Permissions",
"children": [
{
"id": "USER",
"name": "USER",
"children": [
{
"id": "1",
"name": "VIEW"
},
{
"id": "2",
"name": "CREATE"
},
{
"id": "3",
"name": "EDIT"
}
]
},
{
"id": "ROLE",
"name": "ROLE",
"children": [
{
"id": "8",
"name": "VIEW"
},
{
"id": "9",
"name": "CREATE"
},
{
"id": "10",
"name": "EDIT"
},
{
"id": "11",
"name": "DELETE"
}
]
},
{
"id": "DASHBOARD",
"name": "DASHBOARD",
"children": [
{
"id": "BRAND",
"name": "BRAND",
"children": [
{
"id": "52",
"name": "VIEW"
},
{
"id": "53",
"name": "CREATE"
},
{
"id": "54",
"name": "EDIT"
},
{
"id": "55",
"name": "DELETE"
}
]
},
{
"id": "COMPANY",
"name": "COMPANY",
"children": [
{
"id": "56",
"name": "VIEW"
},
{
"id": "57",
"name": "CREATE"
},
{
"id": "58",
"name": "EDIT"
},
{
"id": "59",
"name": "DELETE"
}
]
}
]
}
]
}
I tried various looping method to get the list, e.g. but not returning the exact name of the node.
function getParent(nodes) {
if(Array.isArray(nodes.children)) {
return nodes.children.map((node) => getParent(node));
}
return nodes.name;
}
You can store the resp in an array and return that array.
const q = {
"id": "root",
"name": "Roles and Permissions",
"children": [
{
"id": "USER",
"name": "USER",
"children": [
{
"id": "1",
"name": "VIEW"
},
{
"id": "2",
"name": "CREATE"
},
{
"id": "3",
"name": "EDIT"
}
]
},
{
"id": "ROLE",
"name": "ROLE",
"children": [
{
"id": "8",
"name": "VIEW"
},
{
"id": "9",
"name": "CREATE"
},
{
"id": "10",
"name": "EDIT"
},
{
"id": "11",
"name": "DELETE"
}
]
},
{
"id": "DASHBOARD",
"name": "DASHBOARD",
"children": [
{
"id": "BRAND",
"name": "BRAND",
"children": [
{
"id": "52",
"name": "VIEW"
},
{
"id": "53",
"name": "CREATE"
},
{
"id": "54",
"name": "EDIT"
},
{
"id": "55",
"name": "DELETE"
}
]
},
{
"id": "COMPANY",
"name": "COMPANY",
"children": [
{
"id": "56",
"name": "VIEW"
},
{
"id": "57",
"name": "CREATE"
},
{
"id": "58",
"name": "EDIT"
},
{
"id": "59",
"name": "DELETE"
}
]
}
]
}
]
}
let result = []
function r(nodes){
if(Array.isArray(nodes.children)){
result.push(nodes.name);
nodes.children.map((c) => r(c))
return result;
}
return result;
}
console.log(r(q))
You can simply use a recursive function. Here ids is an array. You can initialize it before calling the function. Call this function in your getting IDs method.
const getIdFromNodesWithChild = (node) => {
if (node.children != undefined){
ids.push(node.id)
const children_list = node.children
children_list.forEach( new_child => getIdFromNodesWithChild(new_child))
}}
caller function
const returnIds = (tree) => {
ids = []
getIdFromNodesWithChild(tree)
return (ids)
}
result : ['root', 'USER', 'ROLE', 'DASHBOARD', 'BRAND', 'COMPANY']
i have an array shared below. I need to change this array like an object. I tried something but cant make it. I Want to make like this with foreach or recursive functions.
let nodes= [
{ id: 1, name: "Denny Curtis", title: "CEO", img: "https://cdn.balkan.app/shared/2.jpg" },
{ id: 2, pid: 1, name: "Ashley Barnett", title: "Sales Manager", img: "https://cdn.balkan.app/shared/3.jpg" },
{ id: 3, pid: 1, name: "Caden Ellison", title: "Dev Manager", img: "https://cdn.balkan.app/shared/4.jpg" }
];
let newObj = {
"id": 1,
"name": "Denny Curtis",
"title": "CEO",
"img": "https://cdn.balkan.app/shared/2.jpg",
"children": [
{
"id": 2,
"pid": 1,
"name": "Ashley Barnett",
"title": "Sales Manager",
"img": "https://cdn.balkan.app/shared/3.jpg",
"children": [
{
"id": 4,
"pid": 2,
"name": "Elliot Patel",
"title": "Sales",
"img": "https://cdn.balkan.app/shared/5.jpg"
},
{
"id": 5,
"pid": 2,
"name": "Lynn Hussain",
"title": "Sales",
"img": "https://cdn.balkan.app/shared/6.jpg"
}
]
}
]
}
Thank you from now.
It would probably be better to make an array of users with the children related to them.
let nodes = [{
id: 1,
name: "Denny Curtis",
title: "CEO",
img: "https://cdn.balkan.app/shared/2.jpg"
},
{
id: 2,
pid: 1,
name: "Ashley Barnett",
title: "Sales Manager",
img: "https://cdn.balkan.app/shared/3.jpg"
},
{
id: 3,
pid: 1,
name: "Caden Ellison",
title: "Dev Manager",
img: "https://cdn.balkan.app/shared/4.jpg"
}
];
let newNodeArray = [];
nodes.forEach(node=>{
newNodeArray.push({...node,children: nodes.filter(filterNode => filterNode.pid === node.id )});
});
console.log(JSON.stringify(newNodeArray));
The outcome of this one would look like:
[
{
"id":1,
"name":"Denny Curtis",
"title":"CEO",
"img":"https://cdn.balkan.app/shared/2.jpg",
"children":[
{
"id":2,
"pid":1,
"name":"Ashley Barnett",
"title":"Sales Manager",
"img":"https://cdn.balkan.app/shared/3.jpg"
},
{
"id":3,
"pid":1,
"name":"Caden Ellison",
"title":"Dev Manager",
"img":"https://cdn.balkan.app/shared/4.jpg"
}
]
},
{
"id":2,
"pid":1,
"name":"Ashley Barnett",
"title":"Sales Manager",
"img":"https://cdn.balkan.app/shared/3.jpg",
"children":[]
},
{
"id":3,
"pid":1,
"name":"Caden Ellison",
"title":"Dev Manager",
"img":"https://cdn.balkan.app/shared/4.jpg",
"children":[]
}
]
//This is how you would do it if you want the response to be an object
let nodeObject = {...nodes.filter(node=>!node.pid)[0],children:[]};
nodeObject.children = nodes.filter(node=>nodeObject.id === node.pid);
nodeObject.children = nodeObject.children.map(node=>({...node,children: nodes.filter(filterNode=>node.id === filterNode.pid)}));
console.log(nodeObject);
// The Response for this would be:
{
"id": 1,
"name": "Denny Curtis",
"title": "CEO",
"img": "https://cdn.balkan.app/shared/2.jpg",
"children": [{
"id": 2,
"pid": 1,
"name": "Ashley Barnett",
"title": "Sales Manager",
"img": "https://cdn.balkan.app/shared/3.jpg",
"children": [{
"id": 4,
"pid": 2,
"name": "Caden Ellison",
"title": "Sales",
"img": "https://cdn.balkan.app/shared/4.jpg"
}]
}, {
"id": 3,
"pid": 1,
"name": "Caden Ellison",
"title": "Dev Manager",
"img": "https://cdn.balkan.app/shared/4.jpg",
"children": []
}]
}
I have a recursive array with same structure of objects and it contains name property. My requirement is to add new property id along with name in recursive array of objects
below is my sample array
[
{
"children": [
{
"children": [
{
"children": [
{
"children": [],
"name": "ID01",
"type": "Under"
},
{
"children": [],
"name": "ID02",
"type": "Under"
}
],
"name": "httpgateway",
"type": "Gut"
},
{
"children": [
{
"children": [],
"name": "mock1",
"type": "Under"
},
{
"children": [],
"name": "mock2",
"type": "Under"
}
],
"name": "mock",
"type": "Gut"
}
],
"name": "23131",
"type": "SEV"
}
],
"name": "integration",
"type": "DataCenter"
},
{
"children": [
{
"children": [
{
"children": [
{
"children": [],
"name": "data1",
"type": "Under"
},
{
"children": [],
"name": "data12",
"type": "Under"
},
{
"children": [],
"name": "data13",
"type": "Under"
},
{
"children": [],
"name": "data14",
"type": "Under"
}
],
"name": "Gut1",
"type": "Gut"
}
],
"name": "213213",
"type": "SEV"
}
],
"name": "dev",
"type": "dt"
}
]
I need Id property along with name as belo
[
{
"children": [
{
"children": [
{
"children": [
{
"children": [],
"name": "ID01",
"id": "ID01",
"type": "Under"
},
{
"children": [],
"name": "ID02",
"id": "ID02",
"type": "Under"
}
],
"name": "gate",
"id": "gate",
"type": "Gut"
},
{
"children": [
{
"children": [],
"name": "mock1",
"id": "mock1",
"type": "Under"
},
{
"children": [],
"name": "mock2",
"id": "mock2",
"type": "Under"
}
],
"name": "mock",
"name": "id",
"type": "Gut"
}
],
"name": "23131",
"id": "23131",
"type": "SEV"
}
],
"name": "int",
"id": "int",
"type": "dt"
},
{
"children": [
{
"children": [
{
"children": [
{
"children": [],
"name": "data1",
"id": "data1",
"type": "Under"
},
{
"children": [],
"name": "data12",
"id": "data12",
"type": "Under"
}
],
"name": "Gut1",
"id": "Gut1",
"type": "Gut"
}
],
"name": "213213",
"id": "213213",
"type": "SEV"
}
],
"name": "dev",
"id": "dev",
"type": "dt"
}
]
I have written method to update this but its not working as expected
const getTreeItemsFromData = (treeItems) => {
console.log('---------------------------', treeItems)
let finalData = []
return treeItems.map((treeItemData) => {
let children = undefined;
if (treeItemData.children && treeItemData.children.length > 0) {
children = this.getTreeItemsFromData(treeItemData.children);
}
let uniqueId = `${treeItemData.name}${Math.floor(Math.random()*(999-100+1)+100)}`;
finalData.push(treeItemData)
console.log("-- ------------------", treeItemData)
});
};
You jus need a function to accept the array and check if the key children exists and is array, make changes to it and then recursively call if it has children.
const t = [
{
"children": [
{
"children": [
{
"children": [
{
"children": [
],
"name": "data1",
"type": "Under"
},
{
"children": [
],
"name": "data12",
"type": "Under"
},
{
"children": [
],
"name": "data13",
"type": "Under"
},
{
"children": [
],
"name": "data14",
"type": "Under"
}
],
"name": "Gut1",
"type": "Gut"
}
],
"name": "213213",
"type": "SEV"
}
],
"name": "dev",
"type": "dt"
}
];
function addIdRec(arr){
arr.forEach(a => {
if(a.children instanceof Array){
a.id = a.name;
if(a.children.length > 0){
addIdRec(a.children);
}
}
})
}
addIdRec(t)
We can do this with a pretty simple recursion:
const addId = (data) =>
data .map (({name, children, ...rest}) =>
({children: addId(children), name, id: name, ...rest})
)
const data = [{children: [{children: [{children: [{children: [], name: "ID01", type: "Under"}, {children: [], name: "ID02", type: "Under"}], name: "httpgateway", type: "Gut"}, {children: [{children: [], name: "mock1", type: "Under"}, {children: [], name: "mock2", type: "Under"}], name: "mock", type: "Gut"}], name: "23131", type: "SEV"}], name: "integration", type: "DataCenter"}, {children: [{children: [{children: [{children: [], name: "data1", type: "Under"}, {children: [], name: "data12", type: "Under"}, {children: [], name: "data13", type: "Under"}, {children: [], name: "data14", type: "Under"}], name: "Gut1", type: "Gut"}], name: "213213", type: "SEV"}], name: "dev", type: "dt"}]
console .log (addId (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
We simply clone the node, adding an id property to match the name one and recur on the children property.
I have a scenario were need to iterate over each children element of the tree structure and modify/add properties or attributes. Each children can have multiple children
var treeStructure = {
"id": 1,
"name": "Grand Parent 1",
"children": [
{
"id": 2,
"children": [
{
"id": 3,
"children": [],
"name": "Child 11",
"properties": [
{
"id": 15,
"run": "fast"
},
{
"id": 16,
"walk": "slow"
}
]
},
{
"id": 4,
"type": "Child",
"children": [],
"name": "Child 12",
"properties": [
{
"id": 17,
"run": "slow"
},
{
"id": 18,
"walk": "medium"
}
]
}
],
"name": "Parent 1",
"properties": [
{
"id": 12,
"run": "slow"
},
{
"id": 13,
"walk": "fast"
}
]
},
{
"id": 5,
"children": [
{
"id": 6,
"children": [],
"name": "Child 21"
}
],
"name": "Parent 2",
"properties": [
{
"id": 21,
"run": "medium"
},
{
"id": 22,
"walk": "fast"
}
]
},
{
"id": 7,
"type": "Parent",
"children": [
{
"id": 8,
"children": [],
"name": "Child 31"
}
],
"name": "Parent 3",
"properties": [
{
"id": 31,
"run": "fast"
},
{
"id": 32,
"walk": "slow"
}
]
}
]
}
iterateTree(treeStructure)
iterateTree (node) {
var self = this;
function recursive(obj) {
if (obj.children && obj.children.length) {
obj.children.forEach(function(val,key){
if(val.hasOwnProperty("children")){
self.modifyProperties(val);
recursive(val.children);
}
})
}
}
var expectedOutput = recursive(node);
console.log(expectedOutput)
}
modifyProperties(nodeData) {
let thingProperties = [];
if (nodeData.properties) {
nodeData.properties.map(function (property) {
let tempObj = {
"id": null,
"actionType": "create",
"run" : property.run
};
thingProperties.push(tempObj);
})
}
return {
"id": nodeData.id,
"name": nodeData.name,
"actionType": "create",
}
}
Expected Output: I should be able to modify "id" as null and add
"actionType" as create for children and parent element as shown below
{
"id": 1,
"name": "Grand Parent 1",
"actionType": "create",
"children": [
{
"id": 2,
"actionType": "create",
"children": [
{
"id": 3,
"children": [],
"name": "Child 11",
"actionType": "create",
"properties": [
{
"id": null,
"run": "fast",
"actionType": "create",
"read": "slow"
},
{
"id": null,
"actionType": "create",
"walk": "slow",
"write": "fast"
}
]
},
{
"id": 4,
"type": "Child",
"children": [],
"name": "Child 12",
"actionType": "create",
"properties": [
{
"id": null,
"actionType": "create",
"run": "slow"
},
{
"id": null,
"actionType": "create",
"walk": "medium"
}
]
}
],
"name": "Parent 1",
"actionType": "create",
"properties": [
{
"id": null,
"actionType": "create",
"run": "slow"
},
{
"id": null,
"actionType": "create",
"walk": "fast"
}
]
},
{
"id": 5,
"children": [
{
"id": null,
"children": [],
"name": "Child 21"
}
],
"name": "Parent 2",
"actionType": "create",
"properties": [
{
"id": null,
"actionType": "create",
"run": "medium"
},
{
"id": null,
"walk": "fast"
}
]
},
{
"id": 7,
"type": "Parent",
"actionType": "create",
"children": [
{
"id": null,
"actionType": "create",
"children": [],
"name": "Child 31"
}
],
"name": "Parent 3",
"properties": [
{
"id": null,
"actionType": "create",
"run": "fast"
},
{
"id": null,
"actionType": "create",
"walk": "slow"
}
]
}
]
}
I have below JavaScript with n level children and want to search for id and if any of item from has matching id than need to return object from root to matching item.
I want to return entire hierarchy of found item from root till object with it's children.
I tried with lodash and underscore and could not find easy solution.
input: {
"children": [{
"name": "Home",
"title": "Home",
"id": "home1",
"children": []
},
{
"name": "BUSINESS AND ROLE SPECIFIC",
"title": "BUSINESS AND ROLE SPECIFIC",
"id": "BAR1",
"children": [{
"name": "Global Businesses",
"title": "Global Businesses",
"id": "GB1",
"children": [{
"name": "Commercial Banking",
"title": "Commercial Banking",
"id": "CB1",
"children": [{
"name": "FLAGSHIP PROGRAMMES",
"title": "FLAGSHIP PROGRAMMES",
"id": "FG1",
"children": []
}]
}]
}]
},
{
"name": "RISK MANAGEMENT",
"title": "RISK MANAGEMENT",
"id": "RM1",
"children": []
}
]
}
Search: {
id: 'FG1'
}
return :{
"name": "BUSINESS AND ROLE SPECIFIC",
"title": "BUSINESS AND ROLE SPECIFIC",
"id": "BAR1",
"children": [{
"name": "Global Businesses",
"title": "Global Businesses",
"id": "GB1",
"children": [{
"name": "Commercial Banking",
"title": "Commercial Banking",
"id": "CB1",
"children": [{
"name": "FLAGSHIP PROGRAMMES",
"title": "FLAGSHIP PROGRAMMES",
"id": "FG1",
"children": [{}]
}]
}]
}]
}
You could use this function:
function findChild(obj, condition) {
if (Object.entries(condition).every( ([k,v]) => obj[k] === v )) {
return obj;
}
for (const child of obj.children || []) {
const found = findChild(child, condition);
// If found, then add this node to the ancestors of the result
if (found) return Object.assign({}, obj, { children: [found] });
}
}
// Sample data
var input = { "children": [{ "name": "Home", "title": "Home", "id": "home1", "children": [] }, { "name": "BUSINESS AND ROLE SPECIFIC", "title": "BUSINESS AND ROLE SPECIFIC", "id": "BAR1", "children": [{ "name": "Global Businesses", "title": "Global Businesses", "id": "GB1", "children": [{ "name": "Commercial Banking", "title": "Commercial Banking", "id": "CB1", "children": [{ "name": "FLAGSHIP PROGRAMMES", "title": "FLAGSHIP PROGRAMMES", "id": "FG1", "children": [] }] }] }] }, { "name": "RISK MANAGEMENT", "title": "RISK MANAGEMENT", "id": "RM1", "children": [] } ]},
search = { id: 'FG1' };
console.log(findChild(input, search));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use this also for searching with multiple conditions, which must be true at the same time:
search = { "name": "Global Businesses", "title": "Global Businesses" };
... would give you the object that has the specified name and title.
Follow-up question
You asked in comments:
Is there way to supply number to not remove children for given node in input. like,
const donotRemoveChildNode = 2;
console.log(findChild(input, search, donotRemoveChildNode ));
...so it will not remove that specific node's children if it matches condition?
Here, if we search for { id: 'FG1'} and supply donotRemoveChildNode = 2, it would not remove the first level children for "Commercial banking".
I would say the donotRemoveChildNode would have to be 3, as there are three levels of children arrays in the ancestor-hierarchy of the "Commercial banking" node. A value of 0 would show the first level children of the top-most children property.
Here is how that extra argument would work -- I added some records to the data to illustrate the difference in the output:
function findChild(obj, condition, removeChildNodesBefore = Infinity) {
if (Object.entries(condition).every( ([k,v]) => obj[k] === v )) {
return obj;
}
for (const child of obj.children || []) {
let found = findChild(child, condition, removeChildNodesBefore - 1);
if (found) {
return Object.assign({}, obj, {
children: removeChildNodesBefore <= 0
? obj.children.map( sibling =>
sibling == child ? found
: Object.assign({}, sibling, {children: []})
)
: [found]
});
}
}
}
var input = { "children": [{ "name": "Home", "title": "Home", "id": "home1", "children": [] }, { "name": "BUSINESS AND ROLE SPECIFIC", "title": "BUSINESS AND ROLE SPECIFIC", "id": "BAR1", "children": [{ "name": "Global Businesses", "title": "Global Businesses", "id": "GB1", "children": [{ "name": "test", "title": "test", "id": "xxx", "children": [{ "name": "testDeep", "title": "test", "id": "deep", "children": []}]}, { "name": "Commercial Banking", "title": "Commercial Banking", "id": "CB1", "children": [{ "name": "test", "title": "test", "id": "yyy", "children": []}, { "name": "FLAGSHIP PROGRAMMES", "title": "FLAGSHIP PROGRAMMES", "id": "FG1", "children": [] }] }] }] }, { "name": "RISK MANAGEMENT", "title": "RISK MANAGEMENT", "id": "RM1", "children": [] } ]},
search = { id: 'FG1' }
console.log(findChild(input, search, 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }
function getBranch(branches, leaf_id)
{
var result_branch = null;
branches.some(function(branch, idx) {
if (branch.id == leaf_id) {
result_branch = Object.assign({}, branch);
result_branch.children.forEach(function(child, idx) {
delete result_branch.children[idx].children;
});
return true;
} else {
let target_branch = getBranch(branch.children, leaf_id);
if (target_branch) {
result_branch = Object.assign({}, branch);
delete result_branch.children
result_branch.children = [target_branch];
return true;
}
}
return false;
});
return result_branch;
}
console.log(getBranch(input.children, 'GB1'));
One way is to first loop the root children, and then create another function to see if the Id exists in any of it's children.
var data = {
"children": [{
"name": "Home",
"title": "Home",
"id": "home1",
"children": []
},
{
"name": "BUSINESS AND ROLE SPECIFIC",
"title": "BUSINESS AND ROLE SPECIFIC",
"id": "BAR1",
"children": [{
"name": "Global Businesses",
"title": "Global Businesses",
"id": "GB1",
"children": [{
"name": "Commercial Banking",
"title": "Commercial Banking",
"id": "CB1",
"children": [{
"name": "FLAGSHIP PROGRAMMES",
"title": "FLAGSHIP PROGRAMMES",
"id": "FG1",
"children": []
}]
}]
}]
},
{
"name": "RISK MANAGEMENT",
"title": "RISK MANAGEMENT",
"id": "RM1",
"children": []
}
]
};
function hasId( id, data ) {
if (data.id === id) return true;
if (data.children) {
for (const child of data.children) {
if (hasId( id, child)) return true;
}
}
return false;
}
function search( id, data ) {
for (const child of data.children) {
if (hasId(id, child)) return child;
}
return null;
}
console.log(search( "FG1", data ));