AngularJS:当 parent 具有 ngIf 指令时,为什么我不能向 grandparent 元素添加属性

AngularJS: Why can't I add an attribute to grandparent element when parent has ngIf directive

我正在使用 vanilla AngularJS v1.4.5(没有 jQuery),并希望我的自定义指令在编译时向其 grandparent 元素添加一个属性。

在compile函数中,我可以使用elementparent()方法两次得到grandparent元素,attr()方法添加我的属性。但是,如果 parent 元素具有 ngIf 指令,则 grandparent 元素不会获得该属性。

angular.module('myApp', [])
    .directive('foo', fooDirective)
;

function fooDirective() {
    return {
        compile : compile,
        priority: 601 // ngIf is 600
    };

    function compile(element, attrs) {
        var parent, grandparent;

        parent = element.parent();            
        grandparent = parent.parent();

        parent.attr('foo', 'bar');
        grandparent.attr('foo', 'bar');
    }
}

JSFiddle

这是我所知道的:

如果 parent 元素具有 ngIf 指令,谁能向我解释为什么我不能向指令的 grandparent 元素添加属性?

我还不完全确定为什么会发生这种情况,但是您是否有任何特殊原因为什么要使用编译来执行此操作?我调整了你的指令以使用 link,它似乎工作得很好。

(function () {
    'use strict';

    angular.module('myApp', [])
        .directive('foo', fooDirective)
    ;

    function fooDirective() {
        return {
            link : link,
            priority: 601 // ngIf is 600
        };

        function link($scope, element, attrs) {
            var parent, grandparent;

            parent = element.parent();            
            grandparent = parent.parent();           
            parent.attr('foo', 'bar');
            grandparent.attr('foo', 'bar');
        }
    }

})();

编辑: 就像@NewDev 说的那样,您通常应该在 link 阶段而不是在编译期间进行 DOM 操作。

所以,重申一下,问题是,为什么给出以下内容:

<grand-parent>
  <parent ng-if="condition">
    <foo></foo>
  </parent>
</grand-parent>

尝试从 foo 的编译中检索 var grandparent = tElement.parent().parent() 时,grandparent 未引用 <grand-parent> 元素。

答案是因为ngIf引起的包含,即使condition === true.

嵌入是将内容(或元素 + 内容,取决于嵌入的类型)从 DOM 中抽出、编译,然后作为克隆提供给包含函数,它本身可用作 link 函数的第 5 个参数:

link: function(scope, element, attrs, ctrls, transcludeFn){
  transcludeFn(scope, function cloneAttachFn(clonedContent){

    // clonedContent is the subtree that was transcluded, compiled and cloned
    element.append(clonedContent);
  });
}

因此,编译过程从 <grand-parent> 开始,然后转到 <parent>,在那里它看到一个指令 - ngIf。因为 ngIftransclude: "element",它从 DOM 中抽取 <parent><foo></foo></parent>,然后编译它。因此,编译继续在 <parent> 上编译其他优先级较低的指令(如果可用),然后编译 foo 指令。

此时,<foo> 不在 <grand-parent> 之下,tElement.parent().parent() 产生 []