Artem Z Artem Z - 4 months ago 13
AngularJS Question

Angular.js ng-show and directive doesn't work

I have the following html:

<div class="modal-dialog" ng-controller="modal-ctrl" ng-show="showModal" execute-on-esc>


Angular.js app:

app.controller('modal-ctrl', function($scope) {
$scope.showModal = true;
});

app.directive('executeOnEsc', function ($document) {
return {
restrict: 'A',
link: function (scope) {
return $document.bind('keydown', function(event) {
event.which === 27? scope.showModal = false : false;
});
}
}
});


Everything works well, $scope.showModal chages to false, but ng-show doesn't respond to this change. Why? Console.log shows that $scope.showModal changes.
Where's the problem?

Answer
return $document.bind('keydown', function(event) {
    event.which === 27? scope.showModal = false : 
});

You are creating an event listener, this listener executes outside of an angular digest cycle. As such you have to tell angular to start a new digest cycle in order for the changes to be picked up. You can use scope.$apply to do this:

return $document.bind('keydown', function(event) {
    scope.$apply(function(){
        event.which === 27? scope.showModal = false : 
    });
});

Demo

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

app.controller('modal-ctrl', function($scope) {
  $scope.showModal = true;
});

app.directive('executeOnEsc', function($document) {
  return {
    restrict: 'A',
    link: function(scope) {
      return $document.bind('keydown', function(event) {
        scope.$apply(function() {
          event.which === 27 ? scope.showModal = false : false;
        });
      });
    }
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div class="modal-dialog" ng-controller="modal-ctrl" ng-show="showModal" execute-on-esc>
    My Modal
  </div>
</div>