Question

I have a directive like this, which wraps element with a container.

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>

However, as you see in demo, http://plnkr.co/edit/wOulzF?p=preview, whenever you start typing into the textarea, the element go outside of the container.

If ng-model is not an arr, it works fine.

Anyone can explain this behaviour?

Était-ce utile?

La solution

Your directive is running before ngRepeat. When Angular compiles an ngRepeat it places special comments in the code that it uses as markers. Since your directive is running before those are added to the DOM your wrapper doesn't enclose those important comments. Instead the html that is created initially looks like this:

<!-- 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 -->

When arr is changed then ngRepeat updates the DOM placing the new/updated ngRepeat element where Angular's marker (the comment) is- which is outside your wrapper. So, after arr is changed (and a $digest occurs) your html looks like this:

<!-- 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 -->

To fix this set your directive priority to 1001 or more (ngRepeat has a priority of 1000):

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

Now ngRepeat will manipulate the DOM first so when your directive wraps the element the ngRepeat comments will be wrapped too resulting in the following 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>

And fixing your problem - updated plunker

Autres conseils

You use the same model for your textarea as for your ng-repeat. That means if you change the contents of your textarea you simultaneously change the model of the ng-repeat directive. That in turn causes ng-repeat to get busy again.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top