6

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"}]}');
4
  • Just a typo, I had been experimenting and forgot to change it back before posting. Fixed it here, problem is still the same. Commented Dec 12, 2013 at 3:49
  • 1
    Can you create fiddle for this with some dummy data? Commented Dec 12, 2013 at 3:49
  • Sure thing, might take a few minutes to get it together. Thanks. Commented Dec 12, 2013 at 3:55
  • Here's a fiddle: jsfiddle.net/eRbhm/2 Commented Dec 12, 2013 at 4:17

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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/

1 Comment

Thanks and big thumbs up for that. I tried your first answer and it worked but my code still didn't and I couldn't figure out how yours was fundamentally different than what I was doing. Fixing _.without fixed it instantly, I had totally overlooked it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.