AngularJS更改编译指令的顺序



据我所知,Angular以先到先得的方式编译东西,这有点棘手。我制定了一个指令,将一些元素封装起来,我希望有一个链接属性来查找内容中的内容。

对于一个具体的用例:我正在制作一个输入标签指令,该指令查看第一个输入的内容内部,并将随机生成的id添加到input,将for属性添加到label

这是代码:

// Find the first element with the attribute ng-label-target or the first input and links a label to it
app.directive('ngLabel', function () {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    scope: {
      label: '@',
    },
    template: '<span class="ng-label">' +
                '<label class="ng-label-text">{{label}}</label>' +
                '<span class="ng-label-content" ng-transclude></span>' +
              '</span>',
    link: function (scope, element, attrs) {
      scope.id = scope.id || 'random-id-' + Math.floor(Math.random() * 90000000);
      angular.element(element[0].querySelector('.ng-label-text')).
        attr({for:scope.id});
      var target = angular.element(element[0].querySelector('[ng-label-target]'));
      if (!target || target.length == 0) {
        target = angular.element(element[0].querySelectorAll('input,select,textarea')[0]);
      }
      target.attr({id:scope.id});
    },
  };
});

示例用法:

<ng-label label="Text:">
   <input type="text" ng-model="page.textColor" size="5" maxlength="7" placeholder="e.g. #000" required />
   <input ng-label-target type="color" ng-model="page.textColor" required />
</ng-label>

这本身就很有魅力。

然而,现在我想自动生成几个输入,并使标签指向第一个。问题是,当我在ng-label中执行ng-repeat时,在处理指令后会生成ng-repeat代码,所以实际上什么都找不到。

因此,我的问题是:是否有一种方法可以指定为angular来内外评估嵌套指令,而不是相反?

或者,有没有比我现在做的更好的方法?

我做了一把小提琴来举例说明评估东西的顺序。你可以看到外部指令的值比它的内容小或相等(不能低于微秒,所以我不得不重复一堆):

http://jsfiddle.net/YLM9P/

从角度文档:

优先级当在单个DOM元素上定义了多个指令时,有时需要指定应用指令的顺序。优先级用于在调用指令的编译函数之前对指令进行排序。优先级定义为一个数字。具有更高数字优先级的指令将首先编译。链接前功能也按优先级顺序运行,但链接后功能按相反顺序运行。具有相同优先级的指令的顺序未定义。默认优先级为0。

终端如果设置为true,则当前优先级将是将执行的最后一组指令(当前优先级的任何指令仍将执行,因为相同优先级的执行顺序未定义)。

因此,对于您的问题,我相信将终端属性设置为true将解决您的问题。

app.directive('ngLabel', function () {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    ....
    ....
    terminal: true
});

这个问题和Angular中的许多其他问题一样,可以通过创建一个附加指令来解决:

app.directive('myLabelTarget', function() {
 return {
   require: '^myLabel',
   link: function(scope, element, attrs, myLabelCtrl) {
     myLabelCtrl.doIfFirst(function(id) {
       attrs.$set('id', id);  
     });
   }
 };
});

使用require属性,您可以访问DOM中更高级别的myLabel指令的控制器。

有关工作示例,请参阅此plnkr。

我认为,通过在父元素上添加一个函数表达式(可能传递一个参数),然后从ng repeat中的子元素调用该函数,可以极大地简化代码并消除querySelectorAll(不是非常的Angular风格)。该函数只需设置一个你将要使用的值,一旦设置好,你就知道你有了第一个值,其余的应该被忽略。如果您展示了ng重复输入字段的最终HTML应该是什么样子,我可以更具体一点。

您可以尝试注册一个MutationObserver,它监听添加到DOM中的元素。但这可能会给你的问题带来一点开销——你自己决定;)

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    // you get notified about added DOM elements here
    // check mutation.type if it was an insertion
    // then you handle the first node specifically.
    console.log(mutation.target.nodeName, mutation.type, mutation);
  });
});
var config = {childList: true, attributes: false, characterData: false, subtree: false, attributeOldValue: false, characterDataOldValue: false};
observer.observe(element[0], config);
演示http://plnkr.co/h6kTtq文档https://developer.mozilla.org/en/docs/Web/API/MutationObserver浏览器支持http://caniuse.com/mutationobserver

最新更新