4

I'm trying to create a breadcrumb without using the url (the route provider) and without using jQuery. I have a tree like that

Humans
Trees
Animals
    Cats
    Lions
    Dogs
       Terrier 
       Bulldog
       Cocker
Cars

and I'd like when I click on Cocker to display

Animals / Dogs / Cocker

So, I created a recursive function in order to find parent/parents for each element that I click on but it doesn't work correctly. It finds that an element has a parent, it also finds the first parent of an element but it doesn't show the second parent. For instance instead of

Animals / Dogs / Cocker

it shows

Dogs / Cocker

That's my function

var count = 0;
function iterate(obj) {
    for(var key in obj) {
      var elem = obj[key];
      if(key === "children") {
        count++;
      }
      if(typeof elem === "object") {
        if(elem.children === undefined){
          elem.children = 1;
        }
        if(elem.children.length !==1){
          iterate(elem);
          $scope.showTrail = elem.children;
          $scope.elem = elem;
        }
      }
     }
    if($scope.elem === undefined){
      $scope.elem = {};
      $scope.elem.children = {};
      $scope.elem.roleName = {};
    }

    for (var i = 0; i<$scope.elem.children.length; i++) {
       if($scope.elem.children[i].roleName === selNode.roleName) {
          console.log($scope.elem.roleName + " is a parent of " + selNode.roleName);
       }
    }

  }
iterate($scope.treeData);

and that's the JSON

     [
          { "roleName" : "Humans", "roleId" : "role2", "children" : [
           { "roleName" : "", "roleId" : "role11", "children" : [] }
          ]},
          { "roleName" : "Trees", "roleId" : "role2", "children" : [
           { "roleName" : "", "roleId" : "role11", "children" : [] }
          ]},
          { "roleName" : "Animals", "roleId" : "role2", "children" : [
            { "roleName" : "Cats", "roleId" : "role11", "children" : [
             { "roleName" : "", "roleId" : "role11", "children" : [] }
            ]},
            { "roleName" : "Lions", "roleId" : "role11", "children" : [
             { "roleName" : "", "roleId" : "role11", "children" : [] }
            ]},
            { "roleName" : "Dogs", "roleId" : "role11", "children" : [
              { "roleName" : "Terrier", "roleId" : "role11", "children" : [
               { "roleName" : "", "roleId" : "role11", "children" : [] }
              ]},
              { "roleName" : "Bulldog", "roleId" : "role11", "children" : [
               { "roleName" : "", "roleId" : "role11", "children" : [] }
              ]},
              { "roleName" : "Cocker", "roleId" : "role11", "children" : [
               { "roleName" : "", "roleId" : "role11", "children" : [] }
              ]},
            ]}
          ]},
          { "roleName" : "Cars", "roleId" : "role2", "children" : [
           { "roleName" : "", "roleId" : "role11", "children" : [] }
          ]}
     ]

Any help please, any idea. Thank you very much.

jimakos17
  • 905
  • 4
  • 14
  • 33
  • Could you provide the real data structure (nested objects/arrays)? –  Nov 18 '13 at 16:47
  • create demo in plunker with directive that generates tree. SHould be able to create breadcrumb as attribute while directive gets compiled – charlietfl Nov 18 '13 at 18:12
  • I updated the question by adding a recursive function which finds a parent element but not all the parents of each element. Any help please!!! – jimakos17 Nov 19 '13 at 12:09

3 Answers3

4

You are iterating over the tree, but it won't help if you don't keep some information. The simplest solution to your problem is to build an index of all nodes that points to their parents.

This code will work if roleName has unique values across the whole tree:

var tree = [
    { "roleName" : "Humans", "roleId" : "role2", "children" : []},
    { "roleName" : "Trees", "roleId" : "role2", "children" : []},
    { "roleName" : "Animals", "roleId" : "role2", "children" : [
        { "roleName" : "Cats", "roleId" : "role11", "children" : []},
        { "roleName" : "Lions", "roleId" : "role11", "children" : []},
        { "roleName" : "Dogs", "roleId" : "role11", "children" : [
            { "roleName" : "Terrier", "roleId" : "role11", "children" : []},
            { "roleName" : "Bulldog", "roleId" : "role11", "children" : []},
            { "roleName" : "Cocker", "roleId" : "role11", "children" : []},
        ]}
    ]},
    { "roleName" : "Cars", "roleId" : "role2", "children" : []}
];

var index = {};

function buildIndex(root, children) {
    for(var i in children) {
        index[children[i].roleName] = root;
        buildIndex(children[i].roleName, children[i].children);
    }
}

buildIndex("Root", tree);

function getPath(leaf) {
    return index[leaf] ? getPath(index[leaf]).concat([leaf]) : [leaf];
}

getPath("Bulldog");// returns ["Root", "Animals", "Dogs", "Bulldog"]

JSFiddle: http://jsfiddle.net/E49Ey/

However it has nothing to do with Angular, except the data resides in the scope. If you have a DOM tree built from this data, then you could get the breadcrumb right from the DOM by going up the tree.

Adam
  • 2,897
  • 2
  • 23
  • 23
3

Hey I put together a quick plunkr doing what your looking for... except it doesn't reverse-traverse up the data tree.

http://embed.plnkr.co/wAJYiAjy58vUEsg4Kr2C

If your looking to actually looking to run up the data tree let me know and I'll modify the plunkr

anthony.c
  • 481
  • 4
  • 15
  • When you call showCrumbs() you change the parameters. I want to pass only the name of the selected element. Thank you very much anthony c – jimakos17 Nov 21 '13 at 15:52
1

You can of course solve it with a recursive function similar to what you showed in the question. What about a solution like this:

function getPath(obj, selNode, pathSoFar) {
    if (obj.roleName == selNode.roleName) {
       return pathSoFar + '\\' + obj.roleName;
    }
    else if (obj.children) {
      for (var i=0 ; i<obj.children.length ; i++) {
          var temp = getPath(obj.children[i], selNode, 
                  pathSoFar + '\\' + obj.roleName);
          if (temp != null) {
              return temp;
          }
       }
    }
    return null;
}

getPath(rootObj, selNode, '');

I hope it helps and explains the solution idea.

lex82
  • 11,173
  • 2
  • 44
  • 69