AngularJS:当父有ngIf指令

时间:2015-09-16 23:16:53

标签: javascript angularjs angularjs-directive angularjs-compile jqlite

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

在编译函数中,我可以使用parent()方法element两次来获取祖父元素,并使用attr()方法来添加我的属性。但是,如果 parent 元素具有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(和doesn't have a compile function)。
  • ngIf完全删除并重新创建DOM中的元素(及其子元素),但这不应影响祖父元素或更改其属性。

如果父元素具有ngIf指令,有人可以向我解释为什么我不能在我的指令的祖父元素中添加属性吗?

2 个答案:

答案 0 :(得分:2)

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

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

尝试从var grandparent = tElement.parent().parent()的编译中检索foo时,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()收益[]

答案 1 :(得分:0)

我不完全确定为什么会发生这种情况,但是你有什么特别的理由为什么要用编译来做这件事?我调整了你的指令以使用链接,它似乎工作正常。

(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操作。