2015-10-08 4 views
0

У меня есть глобальный метод наблюдения за нажатиями клавиш во всем приложении. Когда происходит нажатие клавиши, я транслирую событие следующим образом:

var keycodes = { 
    'escape': 27, 
} 

angular.element($window).on('keydown', function(e) { 
    for (var name in keycodes) { 
     if (e.keyCode === keycodes[name]) { 
      $rootScope.$broadcast('keydown-' + name, angular.element(e.target)) 
     } 
    } 
}) 

Это все работает нормально. В моем контроллере, я прослушивайте событие так:

$rootScope.$on('keydown-escape', $scope.hideOverlays) 

Это также работает хорошо, однако, когда я пытаюсь обновить атрибуты объекта $ области видимости, я не вижу правильное поведение в DOM:

$scope.hideOverlays = function() { 
     for (var i=0; i < $scope.gallery.items.length; i++) { 
      $scope.gallery.items[i].overlayShown = false; 
      $scope.gallery.items[i].editing = false; 
     } 
    } 

Когда я вызываю этот метод внутренне с контроллера, все работает нормально, поэтому мне интересно, есть ли что-то, что Угловое делает по-другому в зависимости от способа вызова метода. Я попробовал имя $ scope. $ Apply(). В дополнение к кажущемуся, что это нехорошо, я также получаю сообщение об ошибке, так что там нет кубиков. Любая помощь очень ценится!

+0

Ваш 'keydown' событие в' app.run'? Вы все правильно вводите? [Вот пример скрипта вашего кода] (http://jsfiddle.net/7h61dv1L/1/). В скрипке обязательно зайдите в раздел html, прежде чем нажимать escape, чтобы панель имела фокус. – jnthnjns

ответ

1

Существует много отсутствующего код, который вызывает несколько вопросов, где вы исполняющие свое keydown событие, например, в моем примере, вы увидите, что я поставил его в app.run в Угловом:

// Note you have to inject $rootScope and $window 
app.run(function ($rootScope, $window) { 
    angular.element($window).on('keydown', function (e) { 
     for (var name in keycodes) { 
      if (e.keyCode === keycodes[name]) { 
       $rootScope.$broadcast('keydown-' + name, angular.element(e.target)) 
      } 
     } 
    }) 
}); 

Это позволяет выполнять его до загрузки любых контроллеров.


Затем в контроллер, вместо запуска $scope.$apply вы должны сделать «безопасный» $ объем. $ Применяется метод, который проверяет существующий переваривать или применять фазу, если есть один, то мы не должны применяться, другой мудрый мы можем.

// Again make sure that you have everything you need injected properly. 
// I need $rootScope injected so I can check the broadcast 
app.controller('MainCtrl', ['$scope', '$rootScope', function ($scope, $rootScope) { 
    $scope.hello = "Hello World"; 
    var count = 0; 
    $scope.hideOverlays = function() { 
     count++; 
     $scope.safeApply(function() { 
      $scope.hello = "You pressed the escape key " + count + " times."; 
     }); 

    }; 

    $rootScope.$on('keydown-escape', $scope.hideOverlays); 

    $scope.safeApply = function (fn) { 
     var phase = this.$root.$$phase; 
     // If AngularJS is currently in the digest or apply phase 
     // we will just invoke the function passed in 
     if (phase == '$apply' || phase == '$digest') { 
      // Let's check to make sure a function was passed 
      if (fn && (typeof (fn) === 'function')) { 
       // Invoke the function passed in 
       fn(); 
      } 
     } else { 
      // If there is no apply or digest in the phase 
      // we will just call $scope.$apply 
      this.$apply(fn); 
     } 
    }; 
}]); 

Here is a working fiddle showing DOM updates when the escape key is pressed

+0

Спасибо! Это сработало, хотя я не совсем уверен, почему. Я уже вызывал событие из app.run, поэтому никакой разницы нет, но метод safeApply, похоже, сделал трюк. Ум объясняет, что там происходит? – jordancooperman

+0

Кроме того, что является лучшим способом сделать этот глобально доступный метод? – jordancooperman

+0

@jordancooperman 'safeApply' действительно проверяет, есть ли активный дайджест или применяется, выполняемый Angluar, он предотвращает ошибку $ scope. $ Apply error, потому что если эта фаза активна только для вызова функции, в противном случае она просто вызовет '$ сфера. $ apply'. Ознакомьтесь с комментариями, которые я добавил. – jnthnjns