Como exibir uma tree recolhível no AngularJS + Bootstrap

Eu estou construindo um aplicativo da web onde eu preciso exibir uma tree usando listas. Minha estrutura básica é assim:

* Node 1 * Node 1.1 * Node 1.1.1 * Node 1.1.1.1 * Node 1.1.2 * Node 1.2 

http://jsfiddle.net/QffFm/1/

Estou tentando encontrar algo em angular ou bootstrap que eu possa usar de forma que:

  • Na primeira vista da lista, ela é expandida até a terceira camada. No meu violino, eu gostaria de ver o Nó 1, Nó 1.1, Nó 1.1.1, Nó 1.1.2 e Nó 1.2 (todos exceto a 4ª camada – Nó 1.1.1.1)
  • Ao clicar no ícone de estilo de lista (não no nome da palavra do nó), o nó recolhe ou expande
  • Idealmente, eu adoraria que o ícone mudasse, dependendo também se o item fosse expandido. Uma seta para a direita se houver mais abaixo, uma seta para baixo se já estiver expandida e talvez um item de lista normal se não houver filhos

Eu sou muito novo no AngularJS e ainda novo no Bootstrap também. Eu vejo que Angular tem uma function de acordeão que não parece lidar com tudo o que eu preciso.

Eu adoraria alguma direção sobre a melhor abordagem antes de codificar muita lógica em meu aplicativo da web que lida com os diferentes casos. Eu acho que isso deve ser um problema comum, então talvez haja algo pronto que eu possa utilizar. Qualquer orientação seria muito apreciada.

Código HTML:

 

Código angular:

 var app = angular.module('myApp', []); app.controller('controller', function ($scope){ $scope.tree=[{"name":"Node 1","items":[{"name":"Node 1.1","items":[{"name":"Node 1.1.1","items":[{"name":"Node 1.1.1.1","items":[]}]},{"name":"Node 1.1.2","items":[]}]},{"name":"Node 1.2","items":[]}]}]; }); app.directive('tree', function() { return { template: '
    ', restrict: 'E', replace: true, scope: { items: '=items', } }; }); app.directive('treeNode', function($compile) { return { restrict: 'E', template: '
  • {{item.name}}
  • ', link: function(scope, elm, attrs) { if (scope.item.items.length > 0) { var children = $compile('')(scope); elm.append(children); } } }; });

    No exemplo a seguir, usei:

    • bootstrap
    • AngularJS recursivo ng-include ou (veja o segundo exemplo) diretivas recursivas
    • jQuery (tentará evitar no futuro)

    Demo 1 ( ng-include ) Plunker

    insira a descrição da imagem aqui

    Deste modelo:

      $scope.displayTree = [{ "name": "Root", "type_name": "Node", "show": true, "nodes": [{ "name": "Loose", "group_name": "Node-1", "show": true, "nodes": [{ "name": "Node-1-1", "device_name": "Node-1-1", "show": true, "nodes": [] }, { "name": "Node-1-2", "device_name": "Node-1-2", "show": true, "nodes": [] }, { "name": "Node-1-3", "device_name": "Node-1-3", "show": true, "nodes": [] }] }, { "name": "God", "group_name": "Node-2", "show": true, "nodes": [{ "name": "Vadar", "device_name": "Node-2-1", "show": true, "nodes": [] }] }, { "name": "Borg", "group_name": "Node-3", "show": true, "nodes": [] }, { "name": "Fess", "group_name": "Node-4", "show": true, "nodes": [] }] }]; [{ "name": "Android", "type_name": "Android", "icon": "icon-android icon-3", "show": true, "nodes": [] }]; } 

    O segundo exemplo é baseado em duas diretivas:

     app.directive('nodeTree', function() { return { template: '', replace: true, transclude: true, restrict: 'E', scope: { tree: '=ngModel' } }; }); app.directive('node', function($compile) { return { restrict: 'E', replace:true, templateUrl: 'the-tree.html', link: function(scope, elm, attrs) { // .... if (scope.node.children.length > 0) { var childNode = $compile('
    ')(scope) elm.append(childNode); } } }; });

    (Adicionadas algumas checkboxs de seleção também 🙂

    Demo 2 Plunker

    Como parece:

    insira a descrição da imagem aqui