Вывод древовидных данных в AngularJS

  • 1,179
  • 0
  • 0
  • 0
  • 1 год назад

Недавно мне довелось столкнуться с проблемой вывода древовидного меню в AngularJS. API возвращает дочерние страницы по id родительской. Например, GET /documents/1 отдает все подстраницы страницы 1. При нажатии на одну из дочерних страниц, вы получаете дочерние страницы следующего уровня.

Глубина дерева заранее неизвестна. Пример JSON ответа:

[
 {
   id: 1,
   name: 'Folder A',
   hasChildren: true
 },

 {
   id: 2,
   name: 'Folder B',
   hasChildren: true
 },

 {
   id: 3,
   name: 'Page A',
   hasChildren: false
 }
]

Для того, чтобы вывести дерево мне необходимо обработать данные рекурсивно. Я решил применить шаблон компоновщик и создать ряд директив для обработки логики. Директива выглядит следующим образом:

<document-tree documents="documents"></document-tree>

Реализация:

angular.module('application')
 .directive('documentTree', function() {
   return {
     scope: {
       documents: '='
     },
     restrict: 'E',
     template: [
       '<ol class="list-group">',
         '<li ng-repeat="child in documents.children" class="list-group-item">',
           '<document-tree-node child="child">',
             '<a ng-click="documents.open(child)" href="javascript:void(0);">',
               '',
             '</a>',
           '</document-tree-node>',
         '</li>',
       '</ol>'
     ].join("")
   };
 })

 .directive('documentTreeNode', function($interpolate, $compile) {
   return {
     scope: {
       child: '='
     },
     restrict: 'E',

     link: function(scope, element) {
       var treeNode = {
         init: function() {
           // Init any vars
           scope.$watch('child.isExpanded', this.toggle.bind(this));
         },

         expand: function() {
           this.domId = 'document-children-' + scope.child.id;

           // Insert child documents
           var template = '<document-tree id="" documents="child.documents"></document-tree>',
               html = $interpolate(template)({ childrenId: this.domId }),
               childrenElement = $compile(html)(scope);

           // Insert compiled template
           element.append(childrenElement);
         },

         collapse: function() {
           // Remove child elements, if needed
           $('#' + this.domId).remove();
         },

         toggle: function(shouldExpand) {
           if (shouldExpand) {
             this.expand();
           } else {
             this.collapse();
           }
         }
       };

       // Init
       treeNode.init();
     }
   };
 });

Как видите, documentTreeNode создает сам себя при наличии ветвей в дереве. Он должен быть создан вручную, иначе будет вызвана ошибка при компиляции если вы применяете рекурсию в шаблоне.

Корневой объект documents это корень дерева данных, полученных от API. Получение данных от API лежит на плечах модели Documents.

Комментарии

0