0

I have a simple button directive that notifies the controller when the button is clicked. However I do not understand why I need to add $scope.$digest() in order for the action to update the scope. See code:

var myModule = angular.module("myModule", []);

myModule.directive("myDirective", function() {
  return {
    restrict: "A",
    scope: {
      action: "&"
    },
    link: function(scope, element, attrs) {
      element.bind("click", function() {
        scope.action();
      });
    }
  };
});

myModule.controller("TestCtrl", function($scope) {
  $scope.divShow = false;
  $scope.buttonClick = function() {
    $scope.divShow = !$scope.divShow;
    // why is this needed?
    $scope.$digest();
  }
});
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<body ng-app="myModule">
  <div ng-controller="TestCtrl">
    <button my-directive action="buttonClick()">Click</button>
    <div ng-show="divShow">
      Div is shown
    </div>
  </div>
</body>

</html>

Here's a jsfiddle

Craig
  • 770
  • 3
  • 14
  • 26
  • Because a DOM event (`element.bind()`) doesn't automatically trigger a digest cycle. – Blackhole Dec 03 '14 at 15:47
  • This is true. If I were using ng-click then I wouldn't need to worry about calling digest since it's called automatically. Instead I'm handing the event handler via click and therefore responsible to run the digest cycle. Thanks! – Craig Dec 03 '14 at 15:49

1 Answers1

1

You should not run a digest cycle yourself (see AngularJS docs) instead, you can run the function in a scope.$evalAsync / scope.$apply / $timeout (*) callback, as the scope.action() code is executed "outside" of angular (it is in a normal JS handler) :

link: function(scope, element, attrs) {
    element.bind("click", function() {
        scope.$evalAsync(function(){
            scope.action();
        });
    });
}

**(*) Which one is "best" to use is outside the scope of this answer : **

Community
  • 1
  • 1
mathieu
  • 30,974
  • 4
  • 64
  • 90