包裹时angularjs指令的奇怪行为

时间:2014-01-09 18:36:13

标签: angularjs angularjs-directive angularjs-ng-repeat

我有一个像这样的指令,它用一个容器包装元素。

app.directive('myDirective', function($compile, $timeout) {
  var num=0;
  return {
    link: function(scope, el, attrs) {
      var uniqNum = scope.$index || num++;
      var container = document.createElement('div');
      container.className = "container";
      el.wrap(container);
    }
  };
});

<textarea my-directive ng-repeat="str in arr track by $index" ng-model="arr[$index]">
</textarea>

但是,正如您在演示文稿http://plnkr.co/edit/wOulzF?p=preview中看到的那样,每当您开始在textarea中输入内容时,该元素就会移出容器。

如果ng-model不是arr,它可以正常工作。

任何人都可以解释这种行为吗?

2 个答案:

答案 0 :(得分:1)

您对textarea使用与ng-repeat相同的模型。这意味着如果您更改textarea的内容,则会同时更改ng-repeat指令的模型。这反过来会导致ng-repeat再次忙碌。

答案 1 :(得分:1)

您的指令在ngRepeat之前运行。当Angular编译ngRepeat时,它会在用作标记的代码中放置特殊注释。由于您的指令在添加到DOM之前运行,因此您的包装器不会包含这些重要注释。相反,最初创建的html如下所示:

<!-- ngRepeat: str in arr track by $index -->
<div class="container">
   <textarea my-directive="" ng-repeat="str in arr track by $index" ng-model="arr[$index]" class="ng-scope ng-pristine ng-valid">  </textarea>
</div>
<!-- end ngRepeat: str in arr track by $index -->

更改arr后,ngRepeat会更新DOM,将新的/更新的ngRepeat元素放置在Angular的标记(注释)所在的位置 - 这不在您的包装器中。因此,在更改arr(并且发生$ digest)之后,您的html看起来像这样:

<!-- ngRepeat: str in arr track by $index -->
   <textarea my-directive="" ng-repeat="str in arr track by $index" ng-model="arr[$index]" class="ng-scope ng-pristine ng-valid">  </textarea>
   <div class="container"> </div>
<!-- end ngRepeat: str in arr track by $index -->

要解决此问题,请将指令优先级设置为1001或更高(ngRepeat的优先级为1000):

return {
    priority: 1001,
    link: function(scope, el, attrs) {.. }
}

现在ngRepeat将首先操作DOM,所以当你的指令包装元素时,ngRepeat注释也将被包装,导致以下html:

<div class="container">
   <!-- ngRepeat: str in arr track by $index -->
    <textarea my-directive="" ng-repeat="str in arr track by $index" ng-model="arr[$index]" class="ng-scope ng-pristine ng-valid">  </textarea>
   <!-- end ngRepeat: str in arr track by $index -->
</div>

修复问题 - updated plunker