For a loop on an object, it gets out of control

I am working with a project that has this crazy loop for expanding nodes in the D3.js interactive canvas. In fact, I want to expand all children. Therefore, if an object has a child, I want to expand it.

I cut a piece of code from this. There is so much for loops that it is ridiculous. How can I reduce this to the simple "find all the children, toggle () and update ();

$('.expandAll').click(function(e) { e.preventDefault(); length = root.children.length; for (var i = 0; i < length; i++) { toggle(root.children[i]); update(root); if (root.children[i]['children']) { childlength = root.children[i]['children'].length; for (var j = 0; j < childlength; j++) { toggle(root.children[i]['children'][j]); update(root); if (root.children[i]['children'][j]['children']) { childlength2 = root.children[i]['children'][j]['children'].length; for (var k = 0; k < childlength2; k++) { toggle(root.children[i]['children'][j]['children'][k]); update(root); } } } } } }); 
+4
source share
3 answers

Sounds good for recursion:

 $('.expandAll').click(function(e) { e.preventDefault(); expandAll(root); }); var expandAll = function (node) { toggle(node); update(node); // edit: if nodes with no children are lacking the children property if (!node.children) { return; } for (var i = 0, length = node.children.length; i < length; i++) { expandAll(node.children[i]); } }; 

I'm not sure what exactly means toggle and update , but you can only make one top-level update call after expandAll(root); .

+3
source

Use recursion ! If you need to support only three levels, you can enter a counter variable for this.

 $('.expandAll').click(function(e) { e.preventDefault(); expandAll(root, root.children/*, 3*/); } function expandAll(root, children/*, lev*/) { if (!children/* || lev<=0 */) return; var length = children.length; for (var i = 0; i < length; i++) { toggle(children[i]); update(root); expandAll(root, children[i].children/*, lev-1*/); } } 

Btw, are you sure you need to call update root after each toggle ? It would be more appropriate for me to call him once at the end, when all the children switch.

0
source

Not sure if this will help, but something that I did with nested objects:

 object = { children: [], // array of similar objects with children property and update function update: function(data){ // update this item this.data = data; // update each immediate child if (this.children) for (var i in this.children) this.children[i].update(data); } }; // then you just call update on the first item: object.update(data); 

If you follow this pattern, instead of setting up complex loops at the root level, you simply iterate over the immediate children and call their update function, which then pushes through their children and goes all the way down.

I am not a great JS developer, only what I did for some nested comments that I worked with on another day;)

0
source

Source: https://habr.com/ru/post/1492333/


All Articles