Art713
Art713

Reputation: 494

Controller firing twice if using $compile on directive

I have a simple angular application thats use directives and dynamically append content to directive using link method. I have to compile that new contents, but if i do so it seems that controller called twice.

app.directive('comment', function ($compile) {
return {
    restrict: 'E',
    template: '<div class="commentItem" ng-controller="MainCtrl">' +
                  '<span class="comment">{{comment.message}}</span>' +
                  '<span class="replyToComment" ng-click="doSmth()">doSmth</span>' + 
              '</div>',
    scope: {
        comment: '='
    },
    link: function (scope, element, attrs) {
        if (angular.isArray(scope.comment.comments)) {
            element.append("<comments comments='comment.comments'></comments>");
            $compile(element.contents())(scope);
        }
    }
};});

Is there a way to avoid this?

I tried to do like described in this post, but that is not work for me.
Here is a plunker.

Upvotes: 2

Views: 2190

Answers (1)

W&#233;dney Yuri
W&#233;dney Yuri

Reputation: 1277

I edited your previous code, sincerely think there is an even better way.

What was happening is that previously you were adding multiple event listeners at the same html element.

Now, i'm destroying everything before compiling again.

app.directive('comment', function ($compile) {
    return {
        restrict: 'E',
        template: '<div class="commentItem">' +
                      '<span class="comment">{{comment.message}}</span>' +
                      '<span class="replyToComment" ng-click="doSmth()">doSmth</span>' + 
                  '</div>',
        scope: {
            comment: '='
        },
        link: function (scope, element, attrs) {
            if (angular.isArray(scope.comment.comments)) {
                element.append("<comments comments='comment.comments'></comments>");
                var html = element.html();
                // Removing all contents and old listeners
                element.contents().remove();
                // Creating a new element
                element.html(html);
                // Adding new listeners
                $compile(element.contents())(scope);
            }
            scope.doSmth = function() {
               alert('!');
            }
        }
    };
});

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

app.controller('MainCtrl', function($scope) {
  $scope.comments = [{
    message: 'parent 1',
    comments: [{
      message: 'p1_child1'
    }, {
      message: 'p1_child2',
      comments: [{
        message: 'p1c2_child1'
      }]
    }]
  },{
    message: 'parent 2'
  },{
    message: 'parent 3'
  }];
});
app.directive('comments', function() {
     return {
         restrict: 'E',
         replace: true,
         template: '<div class="commentBlock">'+
                      '<comment ng-repeat="comment in comments" comment="comment"></comment>' +
                  '</div>',
         scope: {
             comments: '='
         }
     };
});
app.directive('comment', function ($compile) {
    return {
        restrict: 'E',
        template: '<div class="commentItem">' +
                      '<span class="comment">{{comment.message}}</span>' +
                      '<span class="replyToComment" ng-click="doSmth()">doSmth</span>' + 
                  '</div>',
        scope: {
            comment: '='
        },
        link: function (scope, element, attrs) {
            if (angular.isArray(scope.comment.comments)) {
                element.append("<comments comments='comment.comments'></comments>");
                var html = element.html();
                element.contents().remove();
                element.html(html);
                $compile(element.contents())(scope);
            }
            scope.doSmth = function() {
               alert('!');
            }
        }
    };
});
/* Put your css in here */
.commentItem {
  border: 1px dashed black;
  margin: 20px;
}
.replyToComment {
  display: block;
  float: right;
  color: mediumblue;
}
.comment {
  font-size: larger;
  display: block;
  padding-left: 30px;
}
.commentBlock:not(:first-of-type) {
  padding-left: 20px;
}
.replyToComment:hover {
  cursor: pointer;
}
<!DOCTYPE html>
<html ng-app="example">
  <head>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="style.css" />
    <script src="https://code.angularjs.org/1.3.15/angular.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <comments comments="comments"></comments>
  </body>
</html>

Upvotes: 6

Related Questions