简体   繁体   English

如何在子指令之前执行父指令?

[英]How to execute parent directive before child directive?

I'm looking to write two angular directives, a parent and a child directive, to create sortable and cloneable widgets. 我正在寻找两个角度指令,一个父指令和一个子指令,来创建可排序和可复制的小部件。 The intended markup is: 预期的标记是:

<div class="widget-container" data-sortable-widgets>
      <section class="widget" data-cloneable-widget></section>
<div>

However, the child directive seems to execute before the parent, before a certain element is available (its added by the parent): 但是,child指令似乎在父元素之前执行,在某个元素可用之前(由父元素添加):

function SortableWidgetsDirective() {
    return {
        priority: 200,
        restrict: 'A',
        link: function ($scope, element, attrs) {
            element.find(".widget header").append($("<div class='widget-controls'></div>"));
            element.sortable({  });
        }
    };
}

function CloneableWidgetDirective() {
    return {
        priority: 100,
        restrict: 'A',
        link: function ($scope, element, attrs) {
            // This directive wrongfully executes first so widget-controls is no available
            element.find("header .widget-controls").append($("<div class='clone-handle'></div>"));
        }
    };
}

As you can see i tried setting priority but I think because they're on different elements, it does not work. 正如你所看到我尝试设置优先级但我认为因为它们在不同的元素上,它不起作用。

How can I make the parent execute first? 如何让父项先执行?

Reasoning 推理

postLink() is executed in reverse order, which means the child directive's postLink() will be called before the parent's (ie depth first). postLink()以相反的顺序执行,这意味着子指令的postLink()将在父级之前调用(即深度优先)。 For some reason, this is the default behavior ( link() actually refers to postLink() ). 出于某种原因,这是默认行为( link()实际上是指postLink() )。 Luckily we also have preLink() , which works the other way around - we can utilize that to our benefit. 幸运的是,我们还有preLink() ,它以相反的方式工作 - 我们可以利用它来实现我们的利益。

To illustrate this - the following snippet of code: 为了说明这一点 - 以下代码片段:

app.directive('parent', function($log) {
    return {
        restrict: 'E',
        compile: function compile(tElement, tAttrs, transclude) {
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {
                    $log.info('parent pre');
                },
                post: function postLink(scope, iElement, iAttrs, controller) {
                    $log.info('parent post');
                }
            }
        }
    };
});

app.directive('child', function($log) {
    return {
        restrict: 'E',
        compile: function compile(tElement, tAttrs, transclude) {
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {
                    $log.info('child pre');
                },
                post: function postLink(scope, iElement, iAttrs, controller) {
                    $log.info('child post');
                }
            }
        }
    };
});

… will output the following: ...将输出以下内容:

> parent pre
> child pre
> child post
> parent post 

See it live on plunker . 在plunker上看到它。

Solution

If we want the parent directive's logic to be performed before the child's, we will explicitly use preLink() : 如果我们希望在子代之前执行父指令的逻辑,我们将显式使用preLink()

function SortableWidgetsDirective() {
    return {
        restrict: 'A',
        compile: function compile(tElement, tAttrs, transclude) {
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {
                    iElement.find(".widget header").append($("<div class='widget-controls'></div>"));
                    iElement.sortable({});
                },
                post: angular.noop
            }
        }
    };
}

function CloneableWidgetDirective() {
    return {
        restrict: 'A',
        compile: function compile(tElement, tAttrs, transclude) {
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {
                    iElement.find("header .widget-controls").append($("<div class='clone-handle'></div>"));
                },
                post: angular.noop
            }
        }
    };
}

References 参考

  • $compile service on the AngularJS docs. AngularJS文档上的$compile服务。

Post Scriptum Post Scriptum

  • You are correct, by the way - priority is meant for use with directives that share the same element. 顺便说一下,你是正确的 - priority意味着与共享相同元素的指令一起使用。

  • angular.noop is just an empty method that returns nothing. angular.noop只是一个不返回任何内容的空方法。 If you still want to use the postLink() functions, just place the function declaration instead, as you would normally do, ie: 如果您仍想使用postLink()函数,只需放置函数声明,就像通常那样,即:

     post: function postLink(scope, iElement, iAttrs, controller) { ... } 
  • Be ware of the use of templateUrl , as “ Because the template loading is asynchronous the compilation/linking is suspended until the template is loaded ” [source] . 使用templateUrl ,因为“因为模板加载是异步的,所以编译/链接被挂起,直到加载模板” [source] As a result, the order of execution will be disrupted. 结果,执行顺序将被中断。 You can remedy this by including the template inlined in the template property instead. 您可以通过在template属性中包含内联模板来解决此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM