Подтвердить что ты не робот

Почему функция пост-ссылки выполняется до того, как запущенная дочерняя ссылка функционирует?

Сроки использования функций (pre/post) в AngularJS хорошо определены в документации

Функция предварительной привязки

Выполняется до привязки дочерних элементов. Не безопасно делать DOM преобразование, поскольку функция связывания компилятора не сможет найти правильные элементы для соединения.

Функция постсвязывания

Выполняется после того, как дочерние элементы связаны. Безопасно делать DOM преобразование в функции постсвязывания.

и это сообщение в блоге ясно иллюстрирует этот ожидаемый порядок.

Но этот порядок не применяется при использовании ng-transclude и вложенных директив.

Вот пример элемента управления (См. Plunkr)

// index.html
<dropright>
    <col1-item name="a">
        <col2-item>1</col2-item>
        <col2-item>2</col2-item>
    </col1-item>
    <col1-item name="b">
        ...
</dropright>

// dropright-template.html
<div id="col1-el" ng-transclude></div>
<div id="col2-el">
  <!-- Only angularJS will put elements in there -->
</div>

// col1-item-template.html
<p ng-transclude></p>

// col2-item-template.html
<div ng-transclude></div>

Сводка выглядит как

dropright

Директивы записывают журнал в консоль, когда вызывается их связь и функции контроллера. Обычно он отображает:

expected

Но иногда (после нескольких обновлений) порядок не соответствует ожиданиям:

sometimes happen

Функция прямой передачи по прямой выполняется перед функцией post-link своих дочерних элементов.

Возможно, это связано с тем, что в моем конкретном случае я нахожу контроллер dropright в директивах children (См. Plunkr)

angular.module('someApp', [])

.directive('dropright', function() {
    return {
        restrict: 'E',
        transclude: 'true',
        controller: function($scope, $element, $attrs) {
            console.info('controller - dropright');

            $scope.col1Tab = [];
            $scope.col2Tab = [];

            this.addCol1Item = function(el) {
                console.log('(col1Tab pushed)');
                $scope.col1Tab.push(el);
            };

            this.addCol2Item = function(el) {
                console.log('(col2Tab pushed)');
                $scope.col2Tab.push(el);
            };
        },
        link: {
            post: function(scope, element, attrs) {
                console.info('post-link - dropright');
                // Here, I want to move some of the elements of #col1-el
                // into #col2-el
            }
        },
        templateUrl: 'dropright-tpl.html'
    };
})

.directive('col1Item', function($interpolate) {
    return {
        require: '^dropright',
        restrict: 'E',
        transclude: true,
        controller: function() {
            console.log('-- controller - col1Item');
        },
        link: {
            post: function(scope, element, attrs, droprightCtrl) {
                console.log('-- post-link - col1Item');
                droprightCtrl.addCol1Item(element.children()[0]);
            }
        },
        templateUrl: 'col1-tpl.html'
    };      
})

.directive('col2Item', function() {
    var directiveDefinitionObject = {
        require: '^dropright',
        restrict: 'E',
        transclude: true,
        controller: function() {
            console.log('---- controller - col2Item');
        },
        link: {
            post: function(scope, element, attrs, droprightCtrl) {
                console.log('---- post-link - col2Item');
                droprightCtrl.addCol2Item(element.children()[0]);
            }
        },
        templateUrl: 'col2-tpl.html'
    };
    return directiveDefinitionObject;
});

Есть ли какой-либо чистый способ выполнения функции ссылки для директивы после всех функций связи ее дочерних элементов при использовании перехода?

4b9b3361

Ответ 1

Это моя теория - это не аспект трансклюзии, вызывающий проблему последовательности, а шаблон, являющийся templateUrl. Шаблон должен быть разрешен до того, как функция пост-ссылки будет действовать на него, поэтому мы говорим, что функция пост-ссылки безопасна для манипуляций с DOM. Хотя мы получаем 304s для всех трех шаблонов - нам нужно их прочитать, и это в конечном итоге разрешает обещание шаблона.

Я создал плункер с шаблоном вместо templateUrl, чтобы доказать это следствие. У меня есть hot refresh/plunker Stop/Run много раз, но я всегда получаю link - dropright в конце.

Plunker с шаблоном вместо templateUrl

Я не претендую на полное понимание кода compile.js. Однако оказывается, что в   compileTemplateUrl Функция $http.success() разрешает шаблон, а затем при успешном выполнении функция applyDirectivesToNode называется передачей в postLinkFn.

https://github.com/angular/angular.js/blob/master/src/ng/compile.js

Ответ 2

Это может быть просто странность с Plunker. Я попытался скопировать файлы в локальный IIS и не смог реплицировать проблему.