I'm new to Angular, help will be much appreciated. I'm making an app which has different areas, let's call it pages (even though it's truly a 1 page app) for which I naturally use different views, and I have a common layout with the body, styles and scripts etc.
I'm running into a problem in which I want to listen to keyboard events in only one of the pages of the app which is meant to be interactive while the others are administrative. I can bind keyboard events to inputs or to the document or body. Input is not suitable and my document and body are global and I don't want to listen for every single keypress in my app.
What am I supposed to do to solve this problem in Angular?
My code is here: https://github.com/mgenev/geminiFc/blob/master/public/js/controllers/practice.js
I cheated with jQuery and bound the event to the body in the controller for the particular page, but Angular wasn't reacting like an event happened.
$('body').keydown(function(e) {
$scope.changeIndex(e);
});
Then I read I have to use $scope.$apply(); which I did in the bottom of the changeIndex function which the event fires.
This actually worked, but when I call the changeIndex through a click event which is the alternative way of controlling my UI
<div class="practice-controls-bottom">
<i ng-click="changeIndex('down');" class="icon-thumbs-down icon-4x thumbs-down"></i>
<i ng-click="changeIndex('up');" class="icon-thumbs-up icon-4x thumbs-up pull-right"></i>
</div>
Angular gives me an error:
Error: $apply already in progress
at Error (<anonymous>)
at g (http://localhost:3000/lib/angular/angular.min.js:85:37)
at Object.e.$apply (http://localhost:3000/lib/angular/angular.min.js:89:129)
at Object.$scope.changeIndex (http://localhost:3000/js/controllers/practice.js:173:20)
Looking forward to some advice. Thanks!
You can try either one of the following solutions
Call the $scope.$apply in the keydown handler instead of changeindex method
$('body').keydown(function (e) {
$scope.$apply(function () {
$scope.changeIndex(e);
})
});
or check whether the code is running within a apply/digest cycle before calling $apply in changeIndex
again like
if(!$scope.$$phase){
$scope.$apply()
}
Did you have a look at the ng-keypress, ng-keyup, ng-keydown directives? That way, you could only set the directive on the element inside the view you have to listen to keypresses.
Doc: http://docs.angularjs.org/api/ng.directive:ngKeypress
EDIT: Add tabindex="0"
to enable key events on any element.
Here is a working demo: http://plnkr.co/edit/whXgmQU1pKjuRqvokC2Z
html
<div ng-keypress="changeIndex($event)" tabindex="0">Something</div>
js
app.controller('MyCtrl', [function($scope) {
$scope.changeIndex = function($event) {
// $event.keyCode...
}
}]);
There is also a directive in Angular-UI http://angular-ui.github.io/ui-utils/ that let you associate key combinaisons with functions.
<div ui-keypress="{13:'changeIndex($event)'}"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With