40

I am pretty new to AngularJS but found it quite to my liking so far. For my current project I need hotkey functionality and was happy to see that it is supported since the 1.1.2 release.

The ng-keydown directive (http://code.angularjs.org/1.1.3/docs/api/ng.directive:ngKeydown) works as expected for input types but fails me for any other context like div etc. which seems odd given that the documentation says otherwise.

Here is an minimal example (http://jsfiddle.net/TdXWW/12/) of the working respectively the not working:

<input ng-keydown="keypress($event)">
<div ng-keydown="keypress($event)">

NOTE: I know this could be handled with plain jQuery (http://www.mkyong.com/jquery/how-to-check-if-an-enter-key-is-pressed-with-jquery/) but I much prefer to understand how to deal with it in AngularJS.

Lukas N.P. Egger
  • 923
  • 2
  • 9
  • 12
  • 3
    div that isn't `contenteditable` doesn't trigger focus when clciked so there is no active element to bind `keypress` to. Try same thing using jQuery or native script have same problem. Could bind event to document and test that target is not an input. Not sure what your use case is – charlietfl Mar 29 '13 at 15:07

6 Answers6

86

I was having the same problem and was able to fix it by following this simple tip provided in this comment: https://stackoverflow.com/a/1718035/80264

You need to give the div a tabindex so it can receive focus.

<div id="testdiv" tabindex="0"></div>
Community
  • 1
  • 1
João Josézinho
  • 2,648
  • 4
  • 23
  • 27
  • nice very good bit of information. The only issue is then when it gets focus, in FireFox at least, I get a big red border around the element. – Gurnard Mar 06 '14 at 08:48
  • I think that's because of the way firefox handles html form validation by default? See if this helps: http://stackoverflow.com/questions/3809146/firefox-4-required-input-form-red-border-outline – João Josézinho Mar 06 '14 at 13:52
  • Thanks for the link. In the end I added ng-keydown and ng-keyup to the body element that then called functions in the body controller. These then set a variable but could also broadcast to other controllers. Works very well for my needs (selecting data with shift). Thanks for the response. – Gurnard Mar 07 '14 at 09:17
  • 7
    There are not enough upvotes in the world for this. This drove me crazy for like an hour. – TheSoundDefense Jan 15 '16 at 19:53
9

Thanks! To wrap this up I got this working by, injecting $document into my directive, then:

MyApp.directive('myDirective', function($document) {
return {
...
 $document.keydown(function(e){
   console.log(e)
 })
}
Finn Johnsen
  • 635
  • 5
  • 8
8

This was the way I got it working in the end.

Add ng-app to the html element and ng-keyup and ng-keydown to the body element:

<html ng-app="myApp" ng-controller="MainCtrl">
.....
<body ng-keydown="keyPress($event);" ng-keyup="keyRelease($event);">

Then the funcitons in my controller deal with the event calling event.which to get the key code (in my implementation I set a var to the rootScope but you could also broadcast to other controllers)

$scope.keyPress = function(eve) {
    if (eve.which === 16) { // shift
        // $rootScope.$broadcast('doShift');
        $rootScope.shiftOn = true;
    };
};
Gurnard
  • 1,773
  • 22
  • 43
1

The comment by charlietfl cleared things up and binding the event to $(document) worked as expected! Take away message: The AngularJS documentation is not really exhaustive, i.e. demands background knowledge.

Community
  • 1
  • 1
Lukas N.P. Egger
  • 923
  • 2
  • 9
  • 12
0
angular.module('app').directive('executeOnEnter', function () {
    return {
        restrict: 'A',
        link: function (scope, el, attrs, $rootScope) {                      
            $('body').on('keypress', function (evt) {
                if (evt.keyCode === 13) {
                    el.trigger('click', function () {
                    });
                }            
            })

        },
        controller: function ($rootScope) {
            function removeEvent() {
                $("body").unbind("keypress");
            }
            $rootScope.$on('$stateChangeStart', removeEvent);
        }
    }
})
vvn050
  • 194
  • 2
  • 4
  • you are binding keypress on body. So binding continues word event your view has change or when u dont needed that binding to other views. – Gitesh Purbia Jun 05 '17 at 06:17
  • if you are concerned with that, i edited the answer. Of course this might remove something u attached previously to the body (on keypress), so you might want to take care about that. – vvn050 Jun 09 '17 at 10:32
0

it worker fine for me, just add tabindex attribute. make sure that ng-keydown contains correct angularjs expression

    <div ng-keydown="keypress($event)" tabindex="0">

    $scope.keypress = function(ev) {
        console.log('keyprez', ev);
    }
Andrey
  • 1,752
  • 18
  • 17