0

I have a directive that needs to do some HTML rewriting on its contents before it gets compiled. I've found a way to do that but it doesn't seem to work for ng-repeat.

HTML

<body ng-controller="MainCtrl">
  <div ng-repeat="source in sources">
    <p>
        {{ source.name }}
    </p>
  </div>
  <div my-template>
    {{ sources }}
    <div ng-repeat="source in sources">
      <p>
          {{ source.name }}
      </p>
    </div>
</div>
</body>

JS

var app = angular.module('plunker', []);

app.directive("myTemplate", ['$compile', function ($compile) {
  return {
        restrict: 'A',
        link: function ($scope, $element, $attributes) {
            var html = $element.html();
            console.log(html); // problem?
            $element.html(html);
            $compile($element.contents())($scope);
        }
  }
}])

app.controller('MainCtrl', function($scope) {
  $scope.sources = [{ name: "source1"}, { name: "source2"}]; 
});

The output is:

source1

source2

[{"name":"source1"},{"name":"source2"}]

So the sources variable is visible in the directive's scope but ng-repeat fails anyway. console.log(html) shows this in a console:

{{ sources }}
<!-- ngRepeat: source in sources -->

Which hints at ng-repeat being evaluated/compiled before my directive but I don't know where to go further from this.

Plunker: http://plnkr.co/edit/1NJngUK27IRAp0ELVHFc?p=preview

user3601487
  • 1,057
  • 1
  • 11
  • 21
  • 1
    HTML manipulation should be done in the compile phase. For more information see [AngularJS Comprehensive Directive API Reference - compile](https://docs.angularjs.org/api/ng/service/$compile#-compile-). – georgeawg Nov 26 '17 at 19:28

2 Answers2

1

As georgeawg noticed, changing from "link" to "compile" phase helps in this case.

user3601487
  • 1,057
  • 1
  • 11
  • 21
0

You need to use transclude option in directive, see the example. Important you reference a old version of AngularJS (1.0.8), I use in the example 1.4.1.

https://docs.angularjs.org/api/ng/directive/ngTransclude

 angular.module('transcludeExample', [])
   .directive('myTemplate', function(){
      return {
        restrict: 'A',
        transclude: true,
        template: '<ng-transclude></ng-transclude>'
      };
  })
  .controller('ExampleController', ['$scope', function($scope) {
  $scope.sources = [{ name: "source1"}, { name: "source2"}]; 
  }]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.min.js"></script>

<div ng-app="transcludeExample">
<div ng-controller="ExampleController">
  <div my-template>
    {{ sources }}
    <div ng-repeat="source in sources">
      <p>
          {{ source.name }}
      </p>
    </div>
</div>
</div>
</div>
dave008
  • 402
  • 3
  • 9