Skip to content Skip to sidebar Skip to footer

Ng-repeat Doesn't Work When HTML Is Altered Under $compile

Directive code: .directive('replace', function($compile) { return function (scope, element) { element.html(element.html().replace('Hej', 'Hey!')); $compile(el

Solution 1:

The manipulation can also be done in the compile phase:

app.directive("replace", function(){
    return {
        compile: function(element){
            element.html(element.html().replace('Hej', 'Hey!'));
            /*return {
                pre: function(scope, element){
                  element.html(element.html().replace('Hej', 'Hey!'));
                }
            }*/
        }
    };
});

The original problem was caused because the linking of the ng-repeat directive was done before the element with that directive is replaced with the replace operation. The watchers associated with the ng-repeat directive then operate on elements that are no longer attached to the visible DOM.

By moving the replace operation to either the compile phase or the preLink phase, the replacing of the element that has the ng-repeat directive is done before the ng-repeat directive is linked. The watchers associated with ng-repeat directive then work with the replaced DOM.


Solution 2:

You should let Angular and its change detection cycle do the HTML manipulation for you, instead of directly changing it yourself.

I've edited your example to use scope bindings to achieve what you wanted:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example - example-compile-production</title>
  

  <script src="//code.angularjs.org/snapshot/angular.min.js"></script>
  

  
</head>
<body ng-app="compileExample">
  <script>
  angular.module('compileExample', [], function($compileProvider) {
    // configure new 'compile' directive by passing a directive
    // factory function. The factory function injects the '$compile'
    $compileProvider.directive('replace', function($compile) {
        return {
            link: function (scope, element) {
              scope.greeting = 'Hey!';
              $compile(element.contents())(scope);
            }
        }
    });
  })
  .controller('GreeterController', ['$scope', function($scope) {
    $scope.test = [1, 2, 3, 4];
    $scope.greeting = 'Hej';
  }]);
</script>
<div ng-controller="GreeterController">
  <div replace>{{greeting}} <div ng-repeat="e in test">{{ e }}</div></div>
</div>
</body>
</html>

<!-- 
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->

Note: I removed "scope: false" as that is the default behaviour.

EDIT: Since you must replace HTML in place here's a solution with jQuery:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example - example-compile-production</title>
  

  <script src="//code.angularjs.org/snapshot/angular.min.js"></script>
  <script
  src="https://code.jquery.com/jquery-3.1.1.min.js"
  integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
  crossorigin="anonymous"></script>

  
</head>
<body ng-app="compileExample">
  <script>
  angular.module('compileExample', [], function($compileProvider) {
    // configure new 'compile' directive by passing a directive
    // factory function. The factory function injects the '$compile'
    $compileProvider.directive('replace', function($compile) {
        return function (scope, element) {
          $(element).find( ".translation" ).replaceWith("Hey!");
        }
    });
  })
  .controller('GreeterController', ['$scope', function($scope) {
    $scope.arr = [1, 2, 3, 4];
  }]);
</script>
<div ng-controller="GreeterController">
  <div replace><span class="translation">Hej</span> <div ng-repeat="e in arr">{{ e }}</div></div>
</div>
</body>
</html>

<!-- 
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->

Solution 3:

Solved it like this:

.directive("replace", function(){
    return {
        compile: function(){
            return {
                pre: function(scope, element){
                    element.html(element.html().replace('Hej', 'Hey!'));
                }
            }
        }
    };
});

Live example


Post a Comment for "Ng-repeat Doesn't Work When HTML Is Altered Under $compile"