从AngularJS指令添加指令 [英] Add directives from directive in AngularJS

查看:171
本文介绍了从AngularJS指令添加指令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想建立一个指令,需要照顾的添加更多的指令来声明它的元素。
例如,我想建立一个指令,负责加入日期选择器日期选择语言 NG-所需=真

I'm trying to build a directive that takes care of adding more directives to the element it is declared on. For example, I want to build a directive that takes care of adding datepicker, datepicker-language and ng-required="true".

如果我尝试添加的属性,然后使用 $编译我明显产生一个死循环,所以我检查我是否已经添加所需的属性:

If I try to add those attributes and then use $compile I obviously generate an infinite loop, so I am checking if I have already added the needed attributes:

angular.module('app')
  .directive('superDirective', function ($compile, $injector) {
    return {
      restrict: 'A',
      replace: true,
      link: function compile(scope, element, attrs) {
        if (element.attr('datepicker')) { // check
          return;
        }
        element.attr('datepicker', 'someValue');
        element.attr('datepicker-language', 'en');
        // some more
        $compile(element)(scope);
      }
    };
  });

当然,如果我不 $编译元素,属性将被设置,但该指令将不能自举。

Of course, if I don't $compile the element, the attributes will be set but the directive won't be bootstrapped.

这是正确的做法还是我做错了?有没有更好的方法来实现相同的行为?

Is this approach correct or am I doing it wrong? Is there a better way to achieve the same behavior?

UDPATE :鉴于 $编译是实现这一目标的唯一途径,是有办法跳过第一个编译传递(该元素可以包含几个孩子)?也许通过设置端子:真正的

UDPATE: given the fact that $compile is the only way to achieve this, is there a way to skip the first compilation pass (the element may contain several children)? Maybe by setting terminal:true?

更新2 :我试图把指令到选择元素,符合市场预期,编译运行两次,这意味着有预计选项数的两倍秒。

UPDATE 2: I have tried putting the directive into a select element and, as expected, the compilation runs twice, which means there is twice the number of expected options.

推荐答案

在情况下,您有一个单独的DOM元素和地方上的多个指令
为了在他们的应用问题,您可以使用优先级属性命令他们
应用。数值越大,先运行。默认优先级为0,如果你不指定一个。

In cases where you have multiple directives on a single DOM element and where the order in which they’re applied matters, you can use the priority property to order their application. Higher numbers run first. The default priority is 0 if you don’t specify one.

修改:在讨论后,这里的完整的工作方案。关键是要删除属性 element.removeAttr(共同的东西); ,也元素。 removeAttr(数据共东西); (如果用户指定数据共事在html)

EDIT: after the discussion, here's the complete working solution. The key was to remove the attribute: element.removeAttr("common-things");, and also element.removeAttr("data-common-things"); (in case users specify data-common-things in the html)

angular.module('app')
  .directive('commonThings', function ($compile) {
    return {
      restrict: 'A',
      replace: false, 
      terminal: true, //this setting is important, see explanation below
      priority: 1000, //this setting is important, see explanation below
      compile: function compile(element, attrs) {
        element.attr('tooltip', '{{dt()}}');
        element.attr('tooltip-placement', 'bottom');
        element.removeAttr("common-things"); //remove the attribute to avoid indefinite loop
        element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html

        return {
          pre: function preLink(scope, iElement, iAttrs, controller) {  },
          post: function postLink(scope, iElement, iAttrs, controller) {  
            $compile(iElement)(scope);
          }
        };
      }
    };
  });

工作plunker,请访问: http://plnkr.co/edit/Q13bUt?p=$p $ PVIEW

Working plunker is available at: http://plnkr.co/edit/Q13bUt?p=preview

或者

angular.module('app')
  .directive('commonThings', function ($compile) {
    return {
      restrict: 'A',
      replace: false,
      terminal: true,
      priority: 1000,
      link: function link(scope,element, attrs) {
        element.attr('tooltip', '{{dt()}}');
        element.attr('tooltip-placement', 'bottom');
        element.removeAttr("common-things"); //remove the attribute to avoid indefinite loop
        element.removeAttr("data-common-things"); //also remove the same attribute with data- prefix in case users specify data-common-things in the html

        $compile(element)(scope);
      }
    };
  });

演示

解释我们为什么要设置端子:真正的优先级:1000 (高数)

Explanation why we have to set terminal: true and priority: 1000 (a high number):

在DOM就绪,角走DOM来识别所有已注册的指令和编译指令一个接一个基于优先级 如果这些指令都在相同的元素。我们设置我们的自定义指令的优先级为较高的数字,以确保它会被编译第一端子:真正的,其他指令将<该指令被编译后STRONG>跳过即可。

When the DOM is ready, angular walks the DOM to identify all registered directives and compile the directives one by one based on priority if these directives are on the same element. We set our custom directive's priority to a high number to ensure that it will be compiled first and with terminal: true, the other directives will be skipped after this directive is compiled.

当我们自定义指令编制,将通过增加指令和删除自己修改的元素,并使用$编译服务为全部编译指令(包括那些被跳过)

When our custom directive is compiled, it will modify the element by adding directives and removing itself and use $compile service to compile all the directives (including those that were skipped).

如果我们不设置端子:真正的优先级:1000 ,有机会的话,有些指令前我们的自定义指令编译的。而当我们的自定义指令使用$编译编译元素=>重新编译的已编译指令。这将导致未predictable行为,特别是如果之前我们自定义的指令已经改变了DOM编译指令。

If we don't set terminal:true and priority: 1000, there is a chance that some directives are compiled before our custom directive. And when our custom directive uses $compile to compile the element => compile again the already compiled directives. This will cause unpredictable behavior especially if the directives compiled before our custom directive have already transformed the DOM.

有关优先级和终端的更多信息,请查看如何理解`指令terminal`?

For more information about priority and terminal, check out How to understand the `terminal` of directive?

一个指令,它还会修改模板的一个例子是 NG-重复(优先级= 1000),当 NG-重复编译 NG-重复进行其他指令前的模板元素的副本得到应用的。

An example of a directive that also modifies the template is ng-repeat (priority = 1000), when ng-repeat is compiled, ng-repeat make copies of the template element before other directives get applied.

感谢@ Izhaki的评论,下面是引用 ngRepeat 源$ C ​​$ C:<一href=\"https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js\">https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js

Thanks to @Izhaki's comment, here is the reference to ngRepeat source code: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js

这篇关于从AngularJS指令添加指令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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