如何在子指令之前执行父指令? [英] How to execute parent directive before child directive?

查看:28
本文介绍了如何在子指令之前执行父指令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望编写两个 angular 指令,一个父指令和一个子指令,以创建可排序和可克隆的小部件.预期的标记是:

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

然而,子指令似乎在父级之前执行,在某个元素可用(由父级添加)之前:

function SortableWidgetsDirective() {返回 {优先级:200,限制:'A',链接:函数($scope,元素,属性){element.find(".widget header").append($("<div class='widget-controls'></div>"));element.sortable({});}};}函数 CloneableWidgetDirective() {返回 {优先级:100,限制:'A',链接:函数($scope,元素,属性){//该指令首先错误地执行,因此小部件控件不可用element.find("header .widget-controls").append($("<div class='clone-handle'></div>"));}};}

正如你所看到的,我尝试设置优先级,但我认为因为它们位于不同的元素上,所以它不起作用.

如何让父进程先执行?

解决方案

推理

postLink() 以相反的顺序执行,这意味着子指令的 postLink() 将在父指令之前被调用(即深度优先).出于某种原因,这是默认行为(link() 实际上指的是 postLink()).幸运的是,我们还有 preLink(),它可以反过来工作 - 我们可以利用它为我们带来好处.

为了说明这一点 - 以下代码片段:

app.directive('parent', function($log) {返回 {限制:'E',编译:函数编译(tElement,tAttrs,transclude){返回 {前:功能preLink(范围,iElement,iAttrs,控制器){$log.info('parent pre');},后:函数postLink(范围,iElement,iAttrs,控制器){$log.info('父帖子');}}}};});app.directive('child', function($log) {返回 {限制:'E',编译:函数编译(tElement,tAttrs,transclude){返回 {前:功能preLink(范围,iElement,iAttrs,控制器){$log.info('child pre');},后:函数postLink(范围,iElement,iAttrs,控制器){$log.info('子帖子');}}}};});

…将输出以下内容:

>家长预>儿童前>子帖>父帖子

查看 在 plunker 上直播.

解决方案

如果我们希望父指令的逻辑在子指令之前执行,我们将显式使用 preLink():

function SortableWidgetsDirective() {返回 {限制:'A',编译:函数编译(tElement,tAttrs,transclude){返回 {前:功能preLink(范围,iElement,iAttrs,控制器){iElement.find(".widget header").append($("<div class='widget-controls'></div>"));iElement.sortable({});},帖子:angular.noop}}};}函数 CloneableWidgetDirective() {返回 {限制:'A',编译:函数编译(tElement,tAttrs,transclude){返回 {前:功能preLink(范围,iElement,iAttrs,控制器){iElement.find("header .widget-controls").append($("<div class='clone-handle'></div>"));},帖子:angular.noop}}};}

参考文献

<小时>

后脚本

  • 顺便说一句,您是对的 - priority 旨在与共享相同元素的指令一起使用.

  • angular.noop 只是一个不返回任何内容的空方法.如果您仍然想使用 postLink() 函数,只需像通常那样放置函数声明,即:

    post: function postLink(scope, iElement, iAttrs, controller) { ... }

  • 注意templateUrl的使用,因为“因为模板加载是异步的,所以编译/链接会暂停,直到模板加载完毕” [来源].结果,执行顺序将被打乱.您可以通过在 template 属性中包含内联的模板来解决此问题.

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):

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 (i.e. depth first). For some reason, this is the default behavior (link() actually refers to postLink()). Luckily we also have preLink(), which works the other way around - we can utilize that to our benefit.

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.

Solution

If we want the parent directive's logic to be performed before the child's, we will explicitly use 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.

Post Scriptum

  • You are correct, by the way - priority is meant for use with directives that share the same element.

  • angular.noop is just an empty method that returns nothing. If you still want to use the postLink() functions, just place the function declaration instead, as you would normally do, i.e.:

    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]. As a result, the order of execution will be disrupted. You can remedy this by including the template inlined in the template property instead.

这篇关于如何在子指令之前执行父指令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆