2013-10-01 3 views
14

Здесь я нашел отличную директиву деревьев. Original: http://jsfiddle.net/n8dPm/Angularjs: понимание рекурсивной директивы

Я пытался понять его функционирование через пару других вопросов, связанных с вопросами, 1, 2. Я не мог понять, как работают рекурсивные вызовы рендеринга директивы tree. В основном функция компиляции

  1. Когда все функции компиляции называются?
  2. Когда функция $ compile кэшируется в varibale compiledContents (это функция ссылки?), И когда она добавляется? Почему он не прилагается всегда?

-

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); 
       }); 
      }; 
     }, 

ответ

32

Сайт Ng имеет много документации (некоторые из лучших вокруг, на мой взгляд). Обзор петель Startup и времени выполнения очень полезен: http://docs.angularjs.org/guide/concepts

На высоком уровне, когда Ng первым начинает компилирует DOM, начиная где нг-приложение находится (лечение, как только другая директива по Ng). Это означает, что он проходит через элементы и ищет директивы и выражения, которые ему нужно связать с $ rootScope (корень всех областей, которые являются частью прототипической цепи наследования путем процесса компиляции/связывания). Если это директива, процесс компиляции также выполняется на нем. Процесс компиляции принимает все директивы Ng, которые он находит в HTML, и приоритизирует их на основании назначенного приоритета или предполагает, что приоритет равен нулю. Когда они все заказывают, он выполняет функцию компиляции для директивы, которая возвращает функцию ссылки. В приведенном выше примере есть две функции show link, которые я буду комментировать ниже вместе с другими примечаниями, связывающими ее с этим объяснением. функции link также предоставляется HTML, который был в элементе, директива была атрибутом, классом или элементом в виде объекта transclude.

Выполняются функции связи, которые связывают область действия и директив вместе с созданием вида. Это может включать HTML/transclude, поэтому его можно добавить там, где директива ng-transclude находится в шаблоне директивы (которая будет иметь тот же самый процесс, примененный к нему с его шаблоном, являющимся transclude).

Так вот мои примечания к слегка скорректированной таможенной директивы выше:

module.directive("tree", function($compile) { 
    //Here is the Directive Definition Object being returned 
    //which is one of the two options for creating a custom directive 
    //http://docs.angularjs.org/guide/directive 
    return { 
     restrict: "E", 
     //We are stating here the HTML in the element the directive is applied to is going to be given to 
     //the template with a ng-transclude directive to be compiled when processing the directive 
     transclude: true, 
     scope: {family: '='}, 
     template:  
      '<ul>' + 
       //Here we have one of the ng-transclude directives that will be give the HTML in the 
       //element the directive is applied to 
       '<li ng-transclude></li>' + 
       '<li ng-repeat="child in family.children">' + 
        //Here is another ng-transclude directive which will be given the same transclude HTML as 
        //above instance 
        //Notice that there is also another directive, 'tree', which is same type of directive this 
        //template belongs to. So the directive in the template will handle the ng-transclude 
        //applied to the div as the transclude for the recursive compile call to the tree 
        //directive. The recursion will end when the ng-repeat above has no children to 
        //walkthrough. In other words, when we hit a leaf. 
        '<tree family="child"><div ng-transclude></div></tree>' + 
       '</li>' + 
      '</ul>', 
     compile: function(tElement, tAttr, transclude) { 
      //We are removing the contents/innerHTML from the element we are going to be applying the 
      //directive to and saving it to adding it below to the $compile call as the template 
      var contents = tElement.contents().remove(); 
      var compiledContents; 
      return function(scope, iElement, iAttr) { 

       if(!compiledContents) { 
        //Get the link function with the contents frome top level template with 
        //the transclude 
        compiledContents = $compile(contents, transclude); 
       } 
       //Call the link function to link the given scope and 
       //a Clone Attach Function, http://docs.angularjs.org/api/ng.$compile : 
       // "Calling the linking function returns the element of the template. 
       // It is either the original element passed in, 
       // or the clone of the element if the cloneAttachFn is provided." 
       compiledContents(scope, function(clone, scope) { 
         //Appending the cloned template to the instance element, "iElement", 
         //on which the directive is to used. 
         iElement.append(clone); 
       }); 
      }; 
     } 
    }; 
}); 

Всего вещь рабочий: http://jsfiddle.net/DsvX6/7/

+13

Прекрасный пример, но я должен сказать, если это лучший Угловое может, do, то это своего рода безумный способ достичь простой рекурсивной структуры. – acjay

+0

В этом примере добавление функции ссылки в директиву приведет к нарушению процесса? Я не могу заставить его работать – perrohunter

+0

Если я изменил jsfiddle выше, чтобы отложить настройку переменной области видимости (чтобы имитировать получение данных из вызова $ http.get()), он не подбирает изменения. Кто бы вы изменили реализацию, чтобы правильно перестроить дерево при обновлении данных? –

Смежные вопросы