Create dynamic tree widget

1,145 views
Skip to first unread message

Shai Erera

unread,
May 23, 2013, 9:00:41 AM5/23/13
to ang...@googlegroups.com
Hi

I've read a lot about how to create trees with Angular, but none of the examples I found really helped me achieve what I want.
I'm building a UI widget which lets you drill-down on a taxonomy, e.g.:

Date/
  2010/
    March/
      23
      12
    April/
      1
      10
  2011/
    January/
      ...
  ...

The user is first displayed a list of years. He can then choose to expand a year, then displayed a list of months and if he expands a month, he sees dates.
Not all values of year/month/date exist i.e. for a year we're most definitely not going to get back from the taxonomy all the months.
The user also should be able to expand multiple nodes in the hierarchy simultaneously.

My current data model is a JSON record which deliberately keeps the JSON compact, i.e. the above example looks like:
"nodes" : [
  {
    "path" : [ "Date", "2010", "March" ],
    "children" : [
      { "path" : [ "Date", "2010", "March", "23" ] },
      { "path" : [ "Date", "2010", "March", "12" ] },
    ]
  },
  {
    "path" : [ "Date", "2011" ],
    "children" : [
      { "path" : [ "Date", "2011", "January" ] },
      { "path" : [ "Date", "2011", "April" ] },
    ]
  },
  ...
]

Currently the 'path' array of each child contains the full path from root, because it's easier for me that way to process it in Angular, but I think I can optimize it to e.g. include just the leaf.

I am looking for a way to generate such tree in the UI ... I tried to create a directive which recursively goes over the 'path' array and adds "<ul><li>" tags each time writing the next element in the array until it exhausted it and then it writes the children array in a <ul><li> structure. But it just doesn't work .. I'm guessing I either use the wrong tool (directive) or I'm missing something very basic.

I don't want to build the tree in response to button clicks or any user intervention, just populate the DOM with the right structure --- just as what I'd do if I wrote a javascript function which looks up the <div> and sets its innerHTML. I prefer to use the Angular way as much as possible (and also learn it on the way) :).

Thanks in advance,
Shai

Shai Erera

unread,
May 24, 2013, 12:13:34 AM5/24/13
to ang...@googlegroups.com
I ended up writing this link function ... I feel this is not the 'angular' way as I'm practically creating the DOM programmatically, but I've spent the last two days to figure out how to do it otherwise without much success:

        link: function (scope, element, attrs) {
            var elem = element;
            for (var i = 0; i < scope.node.path.length; i++) {
                var newElem = angular.element('<ul class="nav nav-list"><li>' + scope.node.path[i] + '</li></ul>');
                elem.append(newElem);
                console.log(elem);
                elem = newElem;
            }
            var childrenElem = angular.element('<ul class="nav nav-list"></ul>');
            for (var i = 0; i < scope.node.children.length; i++) {
                childrenElem.append(angular.element('<li>' + scope.node.children[i] + '</li>'));
            }
            elem.append(childrenElem);
        }

If there's anyone who knows how to do it the 'angular' way, I'd love to get some tips. I tried playing with the compile function, thinking that maybe I can recursively include <node> elements that way, but the compile function does not have access to the scope and therefore I cannot query how many more nodes I need to create before I create the final list of children ..

The data is going to be more complicated, i.e.each child could be itself a node with sub-children, so I guess my code will need some adjustments.
Really, if there's a better way to achieve that in angular, I'd be happy to learn!

Shai

Sander Elias

unread,
May 24, 2013, 2:35:55 AM5/24/13
to ang...@googlegroups.com
Hi Shai,

have a look at this fiddle (sadly not mine!) It was the cleanest solution I saw up to date!

Regards
Sander

Arnold Bockenbauer

unread,
May 24, 2013, 3:37:39 AM5/24/13
to ang...@googlegroups.com
You should flatten your data, add a 'level' property to each item and them manage a simple bunch of rendering items (using a ng-repeat directive). The level would be virtually rendered with a padding or something like that...

Derek Ekins

unread,
May 24, 2013, 3:58:19 AM5/24/13
to ang...@googlegroups.com
I've had reasonable success with this one https://gist.github.com/furf/4331090

Shai Erera

unread,
May 24, 2013, 8:12:06 AM5/24/13
to ang...@googlegroups.com
Thanks Sander. That is indeed very simple, and above all, works!!! :).

I tried with multi-level hierarchies and it works as expected.
I hope that the real integration ahead of me (with the app itself) will work fine too.

Again, thanks!
Shai

Matt Hardy

unread,
May 24, 2013, 9:45:47 AM5/24/13
to ang...@googlegroups.com
Glad that fiddle was helpful! I created it by combining some ideas based on this thread. We're currently using it in development and it's working great.

Shai Erera

unread,
May 24, 2013, 11:23:40 AM5/24/13
to ang...@googlegroups.com

You rock Matt!

I've only started working with angular recently, and this is the first serious thing I had to accomplish.

I'd like to understand why and how it works. Would you mind explaining it, or point me to some (human/newbie friendly) documentation?

--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/KLXcTZV-DPI/unsubscribe?hl=en-US.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Matt Hardy

unread,
May 24, 2013, 11:36:29 AM5/24/13
to ang...@googlegroups.com
Shai,

Thanks for getting in touch. I'm clearly learning a bit about why it works as well (since that's why I was on the hunt for the recursive example in the first place). 

The key aspect is that we're manually using $compile, instead of letting angular descend into the directive as part of its bootstrapping process. Would be happy to chat more if you like. Feel free to send me any insights of your own.

Matt

Jens Melgaard

unread,
Aug 5, 2014, 10:56:16 AM8/5/14
to ang...@googlegroups.com
Just for others that may pass here...

I created https://github.com/dotJEM/angular-tree to which is merely a way of connecting recursive templates, which is one of the basic building blocks in many of the Angular Tree examples I have seen out there that doesn't end up over complicating things a great deal.

I find it more elegant than the Recursive ng-incude approach, but that is also the one it tries to "improve" on... I don't like the whole Single-Recursive-Directive at all as it isn't as flexible, using a Directive pair, you can suddenly embed one type of tree in another, which would otherwise be problematic with a Single-Recursive-Directive approach...
Reply all
Reply to author
Forward
0 new messages