Alex Reynolds
Alex Reynolds

Reputation: 96947

AngularJS ng-click not firing after compile attempt

I have a template for my directive, which contains a scope variable called content:

<div class="directive-view">
    <span class="directive-header">My Directive</span>
    <span ng-bind-html="content"></span>
</div>

I have the following directive, which watches for changes to content and then compiles the element's contents:

(function () {
    "use strict";

    angular
        .module('myApp.myDirective', [])
        .directive("myDirective", myDirective);

    function myDirective($compile, $sce) {
        return {
            restrict: 'E',
            scope: {
            },
            templateUrl:'../partials/directives/my-directive.html',
            controller: function($scope) {
                $scope.testAlert = function(msg) { alert(msg) };
            },
            link: function (scope, element, attrs, ctrl) {

                scope.content = $sce.trustAsHtml('Initial value');

                scope.$watch(attrs.content, function(value) {
                    element.html(value);
                    console.log("Content changed -- recompiling");
                    $compile(element.contents())(scope);
                });

                scope.content = $sce.trustAsHtml('<button ng-click="testAlert(\'clicked!\')">Click</button>');
            }
        };
    }
})();

The directive renders the button element. However, the controller function testAlert() does not get called when the button element is clicked on.

Also, the $watch callback is called only once, after content is set to Initial value. The callback is not triggered after content is set to the button. (I would have thought that the callback is triggered when the value of attrs.content is changed.)

If I manually recompile the element:

$compile(element.contents())(scope);

the button element still does not trigger the testAlert function when clicked.

How do I correctly recompile the element contents, so that the correct bindings are made?

Upvotes: 0

Views: 1034

Answers (1)

Stepan Kasyanenko
Stepan Kasyanenko

Reputation: 3186

You do not need use $sce in this case. Use just $compile.

Live example on jsfiddle.

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

myApp.controller('MyCtrl', function($scope) {
    $scope.name = 'Superhero';
		$scope.changeTEmplate = function(){
      $scope.cont = '<div><b>i\'m changed</b></div>';
    }
  })
  .directive("myDirective", function myDirective($compile) {
    return {
      restrict: 'E',
      scope: {content:"="},
      template: `<div class="directive-view">
    <span class="directive-header">My Directive</span>
    <span></span>
    </div>`,
      controller: function($scope) {
        $scope.testAlert = function(msg) {
          alert(msg)
        };
      },
      link: function(scope, element, attrs, ctrl) {
        scope.$watch('content', function(value) {
          var span = angular.element(element.find('span')[1]);
          span.html(value);
          console.log("Content changed -- recompiling",value);
            $compile(span)(scope);
        });
        scope.content = '<button ng-click="testAlert(\'clicked!\')">Click</button>';
      }
    };
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
  <div ng-controller="MyCtrl">
    Hello, {{name}}!
    <button ng-click="changeTEmplate()"> change Content</button>
    <my-directive content="cont"></my-directive>
  </div>
</div>

Upvotes: 1

Related Questions