Is it possible to make a Tree View with Angular?

I'm looking to display data in a tree structure in a web app. I was hoping to use Angular for this task.

Looks like ng-repeat will allow me to iterate through a list of nodes, but how can I then do nesting when a given node's depth increases?

I tried the following code, but the auto-escaping of the HTML is preventing this from working. Plus, the end ul tag is in the wrong place.

I'm pretty sure that I'm going about this problem entirely the wrong way.

Any ideas?

Have a look at this fiddle http://jsfiddle.net/brendanowen/uXbn6/8/

This should give you a good idea of how to display a tree like structure using angular. It is kind of using recursion in html!

If you are using Bootstrap CSS...

I have created a simple re-usable tree control (directive) for AngularJS based on a Bootstrap "nav" list. I added extra indentation, icons, and animation. HTML attributes are used for configuration.

It does not use recursion.

I called it angular-bootstrap-nav-tree ( catchy name, don't you think? )

There is an example here, and the source is here.

When making something like this the best solution is an recursive directive. However, when you make such an directive you find out that AngularJS gets into an endless loop.

The solution for this is to let the directive remove the element during the compile event, and manually compile and add them in the link events.

I found out about this in this thread, and abstracted this functionality into a service.

module.factory('RecursionHelper', ['$compile', function($compile){
    return {
        /**
         * Manually compiles the element, fixing the recursion loop.
         * @param element
         * @param [link] A post-link function, or an object with function(s) registered via pre and post properties.
         * @returns An object containing the linking functions.
         */
        compile: function(element, link){
            // Normalize the link parameter
            if(angular.isFunction(link)){
                link = { post: link };
            }

            // Break the recursion loop by removing the contents
            var contents = element.contents().remove();
            var compiledContents;
            return {
                pre: (link && link.pre) ? link.pre : null,
                /**
                 * Compiles and re-adds the contents
                 */
                post: function(scope, element){
                    // Compile the contents
                    if(!compiledContents){
                        compiledContents = $compile(contents);
                    }
                    // Re-add the compiled contents to the element
                    compiledContents(scope, function(clone){
                        element.append(clone);
                    });

                    // Call the post-linking function, if any
                    if(link && link.post){
                        link.post.apply(null, arguments);
                    }
                }
            };
        }
    };
}]);

With this service you can easily make a tree directive (or other recursive directives). Here is an example of an tree directive:

module.directive("tree", function(RecursionHelper) {
    return {
        restrict: "E",
        scope: {family: '='},
        template: 
            '<p>{{ family.name }}</p>'+
            '<ul>' + 
                '<li ng-repeat="child in family.children">' + 
                    '<tree family="child"></tree>' +
                '</li>' +
            '</ul>',
        compile: function(element) {
            return RecursionHelper.compile(element);
        }
    };
});

See this Plunker for a demo. I like this solution best because:

  1. You don't need an special directive which makes your html less clean.
  2. The recursion logic is abstracted away into the RecursionHelper service, so you keep your directives clean.

Update: Added support for a custom linking functions.

This one seems a bit more complete: https://github.com/dump247/angular.tree

Here is an example using a recursive directive: http://jsfiddle.net/n8dPm/ Taken from https://groups.google.com/forum/#!topic/angular/vswXTes_FtM

module.directive("tree", function($compile) {
return {
    restrict: "E",
    scope: {family: '='},
    template: 
        '<p>{{ family.name }}</p>'+
        '<ul>' + 
            '<li ng-repeat="child in family.children">' + 
                '<tree family="child"></tree>' +
            '</li>' +
        '</ul>',
    compile: function(tElement, tAttr) {
        var contents = tElement.contents().remove();
        var compiledContents;
        return function(scope, iElement, iAttr) {
            if(!compiledContents) {
                compiledContents = $compile(contents);
            }
            compiledContents(scope, function(clone, scope) {
                     iElement.append(clone); 
            });
        };
    }
};
});

angular-ui-tree seems to do a good job for me

Another example based off the original source, with a sample tree structure already in place (easier to see how it works IMO) and a filter to search the tree:

JSFiddle

So many great solutions, but I feel they all in one way or another over-complicate things a bit.

I wanted to create something that recreated the simplicity of @Mark Lagendijk's awnser, but without it defining a template in the directive, but rather would let the "user" create the template in HTML...

With ideas taken from https://github.com/stackfull/angular-tree-repeat etc... I ended up with creating the project: https://github.com/dotJEM/angular-tree

Which allows you to build your tree like:

<ul dx-start-with="rootNode">
  <li ng-repeat="node in $dxPrior.nodes">
    {{ node.name }}
    <ul dx-connect="node"/>
  </li>
</ul>

Which to me is cleaner than having to create multiple directives for differently structured trees.... In essence calling the above a tree is a bit false, it picks much more off from @ganaraj's awnser of "recursive templates", but allows us to define the template where we need the tree.

(you could do that with a script tag based template, but it still has to sit right outside the actual tree node, and it still just feels a bit yuk...)

Left here for just another choice...

You can try with Angular-Tree-DnD sample with Angular-Ui-Tree, but i edited, compatibility with table, grid, list.

  • Able Drag & Drop
  • Extended function directive for list (next, prev, getChildren,...)
  • Filter data.
  • OrderBy (ver)

Yes it definitely possible. The question here probably assumes Angular 1.x, but for future reference I am including an Angular 2 example:

Conceptually all you have to do is create a recursive template:

<ul>
    <li *for="#dir of directories">

        <span><input type="checkbox" [checked]="dir.checked" (click)="dir.check()"    /></span> 
        <span (click)="dir.toggle()">{{ dir.name }}</span>

        <div *if="dir.expanded">
            <ul *for="#file of dir.files">
                {{file}}
            </ul>
            <tree-view [directories]="dir.directories"></tree-view>
        </div>
    </li>
</ul>

You then bind a tree object to the template and let Angular work its magic. This concept is obviously applicable to Angular 1.x as well.

Here is a complete example: http://www.syntaxsuccess.com/viewarticle/recursive-treeview-in-angular-2.0

You can use angular-recursion-injector for that: https://github.com/knyga/angular-recursion-injector

Allows you to do unlimited depth nesting with conditioning. Does recompilation only if needed and compiles only right elements. No magic in code.

<div class="node">
  <span>{{name}}</span>

  <node--recursion recursion-if="subNode" ng-model="subNode"></node--recursion>
</div>

One of the things that allows it to work faster and simpler then the other solutions is "--recursion" suffix.