【问题标题】:Why is the post link function executed before the transcluded child link functions?为什么在嵌入的子链接函数之前执行后链接函数?
【发布时间】:2014-10-04 03:54:55
【问题描述】:

AngularJS 中(前/后)链接函数的时间安排在the documentation 中有很好的定义

预链接功能

在链接子元素之前执行。做 DOM 不安全 转换,因为编译器链接函数将无法定位 链接的正确元素。

后链接功能

在子元素链接后执行。做DOM是安全的 后链接功能的转换。

this blog post 清楚地说明了这个预期的顺序。

但在使用ng-transclude 和嵌套指令时,此顺序似乎不适用。

这是一个 dropright 元素的示例 (See the Plunkr)

<!-- index.html -->
<dropright>
  <col1-item name="a">
    <col2-item>1</col2-item>
    <col2-item>2</col2-item>
  </col1-item>
  <col1-item name="b">
    ...
  </col1-item>
</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 看起来像

当调用它们的链接和控制器函数时,指令会在控制台中写入日志。 它通常显示:

但有时(几次刷新后),顺序并不像预期的那样:

dropright post-link 函数在其子项的 post-link 函数之前执行。

这可能是因为,在我的特殊情况下,我在儿童指令中调用 dropright 控制器 (See the 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;
});

在使用转置时,在其子项的所有链接函数之后,是否有任何干净的方法来执行指令的链接函数?

【问题讨论】:

  • 您使用的是哪个版本的 Angular?有许多针对 $compile 的错误修复,特别是与适用于 1.2.18 及更高版本的嵌入相关。请参阅 github.com/angular/angular.js/blob/master/… 的 1.2.18 及更高版本的发行说明
  • @Beyers:我们使用的是1.2.21版本

标签: angularjs angularjs-directive


【解决方案1】:

这可能只是 Plunker 的奇怪之处。我尝试将文件复制到本地 IIS,但无法复制问题。

【讨论】:

  • 我们在本地确实有这个错误,这不仅仅是在 Plunker 上。但如果知道您的机器上有什么不同之处使其能够正常工作会很有趣。
【解决方案2】:

这是我的理论 - 它不是导致序列问题的嵌入方面,而是模板是 templateUrl。模板需要在 post 链接函数对其进行操作之前解析 - 因此我们说 post 链接函数可以安全地进行 DOM 操作。虽然我们为所有 3 个模板获得了 304,但我们确实必须阅读它们,它最终解决了模板承诺。

我用模板而不是 templateUrl 创建了一个 plunker 来证明推论。我有很多次热刷新/plunker Stop/Run,但最后我总是得到link - dropright

Plunker with template instead of templateUrl

我不会假装完全理解 compile.js 代码。然而,似乎在 compileTemplateUrl 函数$http.success() 解析模板,然后在成功时调用applyDirectivesToNode 函数传入postLinkFn

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

【讨论】:

  • 那么就没有办法使用 templateUrl 功能而不出现序列中的这个问题吗?
  • 我觉得这是一个缺陷,或者至少我们需要修复文档,说明后链接功能是基于模板何时解析,我们说它们以相反的顺序运行。这应该是 AngularJS 文档中的一个旁注,因为它的概念对某些人来说有点复杂。创建github.com/angular/angular.js/issues/8631
  • 我认为在父级的 postLink 中“直接”操作内部/子 DOM 可能不是一个好主意,因为“当发生某些事情时 here 改变 DOM there 似乎有点无棱角。如果你描述你打算做什么dropright(外部/父)的postLink,我们可以找到一个更干净的方法。恕我直言,添加/减去新DOM的更干净的方法是ngShow / ngIf,如果我们可以的话很好地装备元模型。
  • 感谢您在 GitHub 上打开问题。事实上,我们不应该依赖 post 链接函数的顺序来进行 DOM 操作。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-03
相关资源
最近更新 更多