Angularjs: понимание рекурсивной директивы
Я нашел здесь большую директиву дерева. Оригинал: http://jsfiddle.net/n8dPm/
Я пытался понять его функционирование через пару других вопросов SO, 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 ответ:
На сайте 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/