Angularjs: понимание рекурсивной директивы


Я нашел здесь большую директиву дерева. Оригинал: http://jsfiddle.net/n8dPm/

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

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

--

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

1 ответ:

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

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

Выполняются функции связи, которые связывают область и директиву вместе с созданием представления. Это может включать HTML / transclude, так что он может быть добавлен, где директива ng-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/