I'm trying to create a function that will generate a tree like structure such that each item contains a reference to it's parent item.
I have a function that calls itself when creating the children but am having a tough time with it, it seems that once it is called from within itself this
still refers to the top level item rather than the current one.
Logging to console what the item is I can see that parent always refers to the first item in the chain (or is absent) when deeper than the first level. It creates the tree, but references to parent are lost for items besides the first.
var Item = function (item, parent) {
console.log('item is :' + item.name);
this.parent = parent;
console.log('parent is: ' + parent);
var fields = _.union(_.keys(item), _.keys(this.parent));
_.each(_.without(fields, ['parent','children']), function (prop) {
this[prop] = angular.isDefined(item[prop]) ? item[prop] : this.parent[prop];
}, this);
this.children = [];
if (item.children) {
this.children = _.map(item.children, function (child) {
console.log('this is : ' + this);
return new Item(child, this)
}, this);
}
};
var tree = new Item(root, {});
Having a bit of trouble getting a fiddle going, but here is some sample data:
var root = JSON.parse('{"id":"1","name":"root item","root":"1","lft":"1","rgt":"22","level":"1","type":
"category","parent_id":"1","deadline":null,
"children":[
{"id":"2","name":"item 1","root":"1","lft":"14","rgt":"15","level":"2","type":"category","parent_id":"1"},
{"id":"6","name":"item 2","root":"1","lft":"16","rgt":"19","level":"2","type":"category","parent_id":"1"},
{"id":"10","name":"item 3","root":"1","lft":"20","rgt":"21","level":"2","type":"item","parent_id":"1"}]}');
The syntax for recursive function is: function recurse() { // function code recurse(); // function code } recurse();
A function can refer to and call itself.
Recursion using mutual function call: (Indirect way) Indirect calling. Though least practical, a function [funA()] can call another function [funB()] which in turn calls [funA()] the former function. In this case, both the functions should have the base case.
Yes, it has to be pass by reference.
The problem is in your usage of the _.without
method. The elements to exclude are passed as a variable number of arguments, not as an array.
Wrong usage:
_.without(['a','b'],['a'])
results in ['a', 'b']
(not what you want)
Whereas:
_.without(['a','b'],'a')
yields your expected result: ['b']
Here's an updated fiddle with the fix.
Note: to avoid the cyclic reference, I print out the parent.id instead of parent
in the "Result" output.
It does the job for me. I simplify the code a bit and added the grandchild item. Have a look:
http://jsfiddle.net/7QYQL/1/
var grandchild = {};
grandchild.name = 'grandchild';
var child = {};
child.name = 'child';
child.children = [];
child.children[0] = grandchild;
var root = {};
root.name = 'root';
root.children = [];
root.children[0] = child;
The problem was _.without() which takes a list rather then an array as a second parameter.
_.without(fields, 'parent','children')
This one works: http://jsfiddle.net/eRbhm/13/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With