AngularJS:为什么当父级有ngIf指令时,我不能向祖父元素添加属性

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

本文关键字:不能 添加 元素 属性 指令 为什么 AngularJS ngIf      更新时间:2023-09-26

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

在编译函数中,我可以使用parent()方法来实现这一点,该方法element两次以获取祖父元素,并使用attr()方法来添加我的属性。但是,如果元素具有 ngIf 指令,则祖父元素不会获取该属性。

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

以下是我所知道的:

  • 如果未在父元素上使用ngIf,则该属性将添加到祖父元素中。
  • 这个问题不应该与scope有关,因为这发生在编译阶段,在范围链接到任何元素之前。
  • 我的编译函数应该在 ngIf 之前运行,它的优先级为 600(并且没有编译函数(。
  • ngIf完全删除并重新创建 DOM 中的元素(及其子元素(,但这不应影响祖父元素或更改其属性。

谁能向我解释一下,如果父元素有 ngIf 指令,为什么我不能向指令的祖父元素添加属性?

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

<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",所以它把<parent><foo></foo></parent>从DOM中拉出来,并编译它。因此,编译继续编译<parent>上的其他低优先级指令(如果可用(,然后编译foo指令。

在这一点上,<foo>没有受到<grand-parent>tElement.parent().parent()收益率[]

我还不完全确定为什么会发生这种情况,但你有什么特殊的原因为什么要使用 compile 这样做吗?我调整了您的指令以使用链接,它似乎工作得很好。

(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说的那样,您通常应该在链接阶段而不是在编译期间进行DOM操作。