428

I want to catch the enter key press event on the textbox below. To make it more clear I am using a ng-repeat to populate the tbody. Here is the HTML:

<td><input type="number" id="closeqty{{$index}}" class="pagination-right closefield" 
    data-ng-model="closeqtymodel" data-ng-change="change($index)" required placeholder="{{item.closeMeasure}}" /></td>

This is my module:

angular.module('components', ['ngResource']);

I am using a resource to populate the table and my controller code is:

function Ajaxy($scope, $resource) {
//controller which has resource to populate the table 
}
sudo bangbang
  • 27,127
  • 11
  • 75
  • 77
Venkata K. C. Tata
  • 5,539
  • 4
  • 22
  • 35

19 Answers19

817

You need to add a directive, like this:

Javascript:

app.directive('myEnter', function () {
    return function (scope, element, attrs) {
        element.bind("keydown keypress", function (event) {
            if(event.which === 13) {
                scope.$apply(function (){
                    scope.$eval(attrs.myEnter);
                });

                event.preventDefault();
            }
        });
    };
});

HTML:

<div ng-app="" ng-controller="MainCtrl">
    <input type="text" my-enter="doSomething()">    
</div>
Alexander Puchkov
  • 5,913
  • 4
  • 34
  • 48
EpokK
  • 38,062
  • 9
  • 61
  • 69
  • 7
    @DerekAdair The directive binds to the `keydown` and `keypress` events of the element it is attributed to. When the event is received the supplied expression is evaluated inside an `$apply` block. – Pete Martin Dec 10 '13 at 02:24
  • 7
    More safe to defined the key like this : ```var key = typeof event.which === "undefined" ? event.keyCode : event.which;``` as long as event.which is not used by every browser. See comments here : http://stackoverflow.com/a/4471635/2547632 – Gabriel Dec 18 '13 at 08:31
  • 3
    I would add also `keyup` in the bind test – user1713964 Jan 03 '14 at 14:40
  • 2
    This is the best solution as it keeps view and controller seperated. – Maya Kathrine Andersen Feb 03 '14 at 22:43
  • 1
    Separating out the actually triggered event handling function into the $scope of the directive allows for easier unit testing, because the fn() can be called directly in the test, instead of having to create and dispatch an actual event. Similar to [the other answer here](http://stackoverflow.com/a/18625831/122764). – Cornelius Feb 11 '14 at 12:34
  • 59
    also note that using ng prefix is not recommended, as this can clash with future ng-* directives. Use your own instead – Marius Balčytis Apr 25 '14 at 00:34
  • 2
    Why is he binding `keydown` and `keypress`. Isn't just enough with `keypress`? – flyer88 Jul 28 '15 at 18:55
  • Does anyone have the tests (jasmine) of that directive :) – Joe Hany Dec 02 '15 at 13:50
  • 3
    Dont forget to destroy your bindings: **scope.$on('$destroy', function(){ element.unbind('keydown'); })** – nawlbergs Jan 28 '16 at 16:50
  • @user1713964 Just use `keydown` or `keyup` if you need `escape` key – Tommy Bjerregaard Mar 01 '16 at 10:37
  • Note, having both keydown and keypress can cause the action to be called twice. Bad news if you're making a server call, submitting a form, etc. – mike Mar 20 '16 at 04:05
  • 1
    `$eval and $parse` evaluate only angular expression. $eval uses $parse internally So $parse can be used instead $eval. scope.$apply is trigger digest loop unnecessarily. Everything is handled by $parse internally. – Mohan Singh May 27 '16 at 07:45
  • 2
    updated directive is here https://gist.github.com/singhmohancs/317854a859098bffe9477f59eac8d915 – Mohan Singh May 27 '16 at 07:54
  • `KeyboardEvent.wich` is now deprecated. You should use `KeyboardEvent.key` instead. Cf [MDN](https://developer.mozilla.org/en/docs/Web/API/KeyboardEvent). – Francois Stock Aug 24 '16 at 16:06
  • Why are you not using ng-keypress, ng-keydown, ng-keyup? The code is cleaner if you do this because then you get the keyCode directly without any binding. You can handle all your keycodes in this one function instead of creating a directive for each key. Or you could create specific key directives (onEnter) but just supply a handler function that your main ng-keydown handler calls. – Ed Greaves Feb 03 '17 at 17:48
  • how would i use it in a nested directive? i.e. I've got a directive with it's own controller and template - when I use it in template it doesn't work. but if I used it outside of the directive, it will work just fine. is there a way to do it within the directive? – user841760 Sep 26 '17 at 16:47
  • It took me a while of debugging to work out that the attribute is "my-enter" with a dash but the directive name is "myEnter" without a dash! – Matthew Mar 15 '18 at 04:11
  • brilliant! Just what I needed – GrahamJRoy May 09 '18 at 09:10
  • @ahnbizcad 13 is the keyCode for the enter key. You can find out which key corresponds to which code by looking up the according tables or by using http://keycode.info – DBX12 Feb 25 '19 at 13:27
  • When I change the name of the directive, for example, myEnter to mdEnter it doesn't work, how can I customize name? – Shervin Ivari Aug 11 '19 at 20:21
361

An alternative is to use standard directive ng-keypress="myFunct($event)"

Then in your controller you can have:

...

$scope.myFunct = function(keyEvent) {
  if (keyEvent.which === 13)
    alert('I am an alert');
}

...
Rahil Wazir
  • 10,007
  • 11
  • 42
  • 64
Chris Reynolds
  • 5,453
  • 1
  • 15
  • 12
  • 19
    To save other people some time, `ng-keypress` doesn't seem to be part of angular 1.0.x, `ui-keypress` (with slightly different calling semantics) is available though: http://angular-ui.github.io/ui-utils/ – Cebjyre Sep 18 '13 at 00:38
  • 1
    I think the comment above this was aimed at a different answer. (Just for reference.) – Cornelius Feb 11 '14 at 12:33
  • Martin that's actually the function of a controller: to handle UI events. – Trevor de Koekkoek Apr 08 '14 at 14:21
  • 5
    Better yet, use ngKeypress and pass the $event to a custom filter. – Martin Oct 02 '14 at 19:28
  • 8
    Best answer +1. Why should I make my own directive, if there is one, already included in Angular? – bFunc Jul 13 '16 at 10:09
  • I was using this with codemirror and it couldn't catch the enter key, probably because it was binded with something else on default. The answer by EpokK works best – Shashank Singh Feb 01 '17 at 21:37
  • way better then creating a whole directive. – Neta Meta May 06 '17 at 23:34
  • Kudos for simplicity. – birdus Sep 20 '17 at 21:28
  • I feel like this is a lot more palatable than creating custom directives, and even if you needed to do this multiple places, it would be simple enough to wrap the conditional logic in a function. `if (isEnterKey($event)) { do stuff... )` – DVK Jun 13 '19 at 14:38
187

My simplest approach using just angular build-in directive:

ng-keypress, ng-keydown or ng-keyup.

Usually, we want add keyboard support for something that already handled by ng-click.

for instance:

<a ng-click="action()">action</a>

Now, let's add keyboard support.

trigger by enter key:

<a ng-click="action()" 
   ng-keydown="$event.keyCode === 13 && action()">action</a>

by space key:

<a ng-click="action()" 
   ng-keydown="$event.keyCode === 32 && action()">action</a>

by space or enter key:

<a ng-click="action()" 
   ng-keydown="($event.keyCode === 13 || $event.keyCode === 32) && action()">action</a>

if you are in modern browser

<a ng-click="action()" 
   ng-keydown="[13, 32].includes($event.keyCode) && action()">action</a>

More about keyCode:
keyCode is deprecated but well supported API, you could use $evevt.key in supported browser instead.
See more in https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key

Eric Chen
  • 3,708
  • 2
  • 18
  • 15
104

Another simple alternative:

<input ng-model="edItem" type="text" 
    ng-keypress="($event.which === 13)?foo(edItem):0"/>

And the ng-ui alternative:

<input ng-model="edItem" type="text" ui-keypress="{'enter':'foo(edItem)'}"/>
19

Here is what I figured out when I was building an app with a similar requirement, it doesn't require writing a directive and it's relatively simple to tell what it does:

<input type="text" ng-keypress="($event.charCode==13)?myFunction():return" placeholder="Will Submit on Enter">
marcinzajkowski
  • 301
  • 3
  • 4
15

You can use ng-keydown ="myFunction($event)" as attribute.

<input ng-keydown="myFunction($event)" type="number">

myFunction(event) {
    if(event.keyCode == 13) {   // '13' is the key code for enter
        // do what you want to do when 'enter' is pressed :)
    }
}
Fineas
  • 151
  • 1
  • 5
7

html

<textarea id="messageTxt" 
    rows="5" 
    placeholder="Escriba su mensaje" 
    ng-keypress="keyPressed($event)" 
    ng-model="smsData.mensaje">
</textarea>

controller.js

$scope.keyPressed = function (keyEvent) {
    if (keyEvent.keyCode == 13) {
        alert('presiono enter');
        console.log('presiono enter');
    }
};
Bubbles
  • 3,795
  • 1
  • 24
  • 25
4

You can also apply it to a controller on a parent element. This example can be used to highlight a row in a table by pressing up/down arrow keys.

app.controller('tableCtrl', [ '$scope', '$element', function($scope, $element) {
  $scope.index = 0; // row index
  $scope.data = []; // array of items
  $scope.keypress = function(offset) {
    console.log('keypress', offset);
    var i = $scope.index + offset;
    if (i < 0) { i = $scope.data.length - 1; }
    if (i >= $scope.data.length) { i = 0; }
  };
  $element.bind("keydown keypress", function (event) {
    console.log('keypress', event, event.which);
    if(event.which === 38) { // up
      $scope.keypress(-1);
    } else if (event.which === 40) { // down
      $scope.keypress(1);
    } else {
      return;
    }
    event.preventDefault();
  });
}]);


<table class="table table-striped" ng-controller="tableCtrl">
<thead>
    <tr>
        <th ng-repeat="(key, value) in data[0]">{{key}}</th>
    </tr>
</thead>
<tbody>
    <tr ng-repeat="row in data track by $index" ng-click="draw($index)" ng-class="$index == index ? 'info' : ''">
        <td ng-repeat="(key, value) in row">{{value}}</td>
    </tr>
</tbody>
</table>

will Farrell
  • 1,733
  • 1
  • 16
  • 21
3

Trying

ng-keypress="console.log($event)"
ng-keypress="alert(123)"

did nothing for me.

Strangley the sample at https://docs.angularjs.org/api/ng/directive/ngKeypress, which does ng-keypress="count = count + 1", works.

I found an alternate solution, which has pressing Enter invoke the button's ng-click.

<input ng-model="..." onkeypress="if (event.which==13) document.getElementById('button').click()"/>
<button id="button" ng-click="doSomething()">Done</button>
snaran
  • 163
  • 8
  • `ng-keypress="console.log('foo')"` did not work for me either, but if you do `ng-keypress="fooMethod()"` and in your controller `$scope.fooMethod = function() { console.log('fooMethod called'); }` does work. – GraehamF Mar 14 '15 at 19:23
3
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
Informe your name:<input type="text" ng-model="pergunta" ng-keypress="pressionou_enter($event)" ></input> 
<button ng-click="chamar()">submit</button>
<h1>{{resposta}}</h1> 
</div>
<script>
var app = angular.module('myApp', []);
//create a service mitsuplik
app.service('mitsuplik', function() {
    this.myFunc = function (parametro) {
        var tmp = ""; 
        for (var x=0;x<parametro.length;x++)
            {
            tmp = parametro.substring(x,x+1) + tmp;
            } 
        return tmp;
    }
});
//Calling our service
app.controller('myCtrl', function($scope, mitsuplik) { 
  $scope.chamar = function() { 
        $scope.resposta = mitsuplik.myFunc($scope.pergunta); 
    };
  //if mitsuplik press [ENTER], execute too
  $scope.pressionou_enter = function(keyEvent) {
             if (keyEvent.which === 13) 
                { 
                $scope.chamar();
                }

    }
});
</script>
</body>
</html>
2

This is an extension on the answer from EpokK.

I had the same problem of having to call a scope function when enter is pushed on an input field. However I also wanted to pass the value of the input field to the function specified. This is my solution:

app.directive('ltaEnter', function () {
return function (scope, element, attrs) {
    element.bind("keydown keypress", function (event) {
        if(event.which === 13) {
          // Create closure with proper command
          var fn = function(command) {
            var cmd = command;
            return function() {
              scope.$eval(cmd);
            };
          }(attrs.ltaEnter.replace('()', '("'+ event.target.value +'")' ));

          // Apply function
          scope.$apply(fn);

          event.preventDefault();
        }
    });
};

});

The use in HTML is as follows:

<input type="text" name="itemname" lta-enter="add()" placeholder="Add item"/>

Kudos to EpokK for his answer.

tassaert.l
  • 101
  • 4
1

What about this?:

<form ng-submit="chat.sendMessage()">
    <input type="text" />
    <button type="submit">
</form>

Now when you push enter key after write something in your input, the form know how to handle it.

juanmorschrott
  • 573
  • 5
  • 25
0

Some example of code that I did for my project. Basically you add tags to your entity. Imagine you have input text, on entering Tag name you get drop-down menu with preloaded tags to choose from, you navigate with arrows and select with Enter:

HTML + AngularJS v1.2.0-rc.3

    <div>
        <form ng-submit="addTag(newTag)">
            <input id="newTag" ng-model="newTag" type="text" class="form-control" placeholder="Enter new tag"
                   style="padding-left: 10px; width: 700px; height: 33px; margin-top: 10px; margin-bottom: 3px;" autofocus
                   data-toggle="dropdown"
                   ng-change="preloadTags()"
                   ng-keydown="navigateTags($event)">
            <div ng-show="preloadedTags.length > 0">
                <nav class="dropdown">
                    <div class="dropdown-menu preloadedTagPanel">
                        <div ng-repeat="preloadedTag in preloadedTags"
                             class="preloadedTagItemPanel"
                             ng-class="preloadedTag.activeTag ? 'preloadedTagItemPanelActive' : '' "
                             ng-click="selectTag(preloadedTag)"
                             tabindex="{{ $index }}">
                            <a class="preloadedTagItem"
                               ng-class="preloadedTag.activeTag ? 'preloadedTagItemActive' : '' "
                               ng-click="selectTag(preloadedTag)">{{ preloadedTag.label }}</a>
                        </div>
                    </div>
                </nav>
            </div>
        </form>
    </div>

Controller.js

$scope.preloadTags = function () {
    var newTag = $scope.newTag;
    if (newTag && newTag.trim()) {
        newTag = newTag.trim().toLowerCase();

        $http(
            {
                method: 'GET',
                url: 'api/tag/gettags',
                dataType: 'json',
                contentType: 'application/json',
                mimeType: 'application/json',
                params: {'term': newTag}
            }
        )
            .success(function (result) {
                $scope.preloadedTags = result;
                $scope.preloadedTagsIndex = -1;
            }
        )
            .error(function (data, status, headers, config) {
            }
        );
    } else {
        $scope.preloadedTags = {};
        $scope.preloadedTagsIndex = -1;
    }
};

function checkIndex(index) {
    if (index > $scope.preloadedTags.length - 1) {
        return 0;
    }
    if (index < 0) {
        return $scope.preloadedTags.length - 1;
    }
    return index;
}

function removeAllActiveTags() {
    for (var x = 0; x < $scope.preloadedTags.length; x++) {
        if ($scope.preloadedTags[x].activeTag) {
            $scope.preloadedTags[x].activeTag = false;
        }
    }
}

$scope.navigateTags = function ($event) {
    if (!$scope.newTag || $scope.preloadedTags.length == 0) {
        return;
    }
    if ($event.keyCode == 40) {  // down
        removeAllActiveTags();
        $scope.preloadedTagsIndex = checkIndex($scope.preloadedTagsIndex + 1);
        $scope.preloadedTags[$scope.preloadedTagsIndex].activeTag = true;
    } else if ($event.keyCode == 38) {  // up
        removeAllActiveTags();
        $scope.preloadedTagsIndex = checkIndex($scope.preloadedTagsIndex - 1);
        $scope.preloadedTags[$scope.preloadedTagsIndex].activeTag = true;
    } else if ($event.keyCode == 13) {  // enter
        removeAllActiveTags();
        $scope.selectTag($scope.preloadedTags[$scope.preloadedTagsIndex]);
    }
};

$scope.selectTag = function (preloadedTag) {
    $scope.addTag(preloadedTag.label);
};

CSS + Bootstrap v2.3.2

.preloadedTagPanel {
    background-color: #FFFFFF;
    display: block;
    min-width: 250px;
    max-width: 700px;
    border: 1px solid #666666;
    padding-top: 0;
    border-radius: 0;
}

.preloadedTagItemPanel {
    background-color: #FFFFFF;
    border-bottom: 1px solid #666666;
    cursor: pointer;
}

.preloadedTagItemPanel:hover {
    background-color: #666666;
}

.preloadedTagItemPanelActive {
    background-color: #666666;
}

.preloadedTagItem {
    display: inline-block;
    text-decoration: none;
    margin-left: 5px;
    margin-right: 5px;
    padding-top: 5px;
    padding-bottom: 5px;
    padding-left: 20px;
    padding-right: 10px;
    color: #666666 !important;
    font-size: 11px;
}

.preloadedTagItem:hover {
    background-color: #666666;
}

.preloadedTagItemActive {
    background-color: #666666;
    color: #FFFFFF !important;
}

.dropdown .preloadedTagItemPanel:last-child {
    border-bottom: 0;
}
Dmitri Algazin
  • 3,332
  • 27
  • 30
  • 2
    I think this is a nasty solution. A controller shouldn't handle UI things like keypresses. – Maya Kathrine Andersen Feb 03 '14 at 22:44
  • 5
    This answer contains a lot of "noise", in a manner of speaking, containing a lot of markup that does — as far as I can see at a glance — not relate to the actual question at hand. It might be more succinct/useful to condense the code in the answer and provide the full example in a gist/jsfiddle/plnkr. – Cornelius Feb 11 '14 at 12:35
  • 1
    @MartinAndersen, where should a keypress be handled in an angular app? – Emanegux Aug 25 '14 at 17:53
  • 1
    When I look at it now it looks okay. It's basically how keypresses has always been handled with the JS event model. – Maya Kathrine Andersen Aug 25 '14 at 21:15
0

I'm a bit late .. but i found a simpler solution using auto-focus .. This could be useful for buttons or other when popping a dialog :

<button auto-focus ng-click="func()">ok</button>

That should be fine if you want to press the button onSpace or Enter clicks .

0

here's my directive:

mainApp.directive('number', function () {
    return {
        link: function (scope, el, attr) {
            el.bind("keydown keypress", function (event) {
                //ignore all characters that are not numbers, except backspace, delete, left arrow and right arrow
                if ((event.keyCode < 48 || event.keyCode > 57) && event.keyCode != 8 && event.keyCode != 46 && event.keyCode != 37 && event.keyCode != 39) {
                    event.preventDefault();
                }
            });
        }
    };
});

usage:

<input number />
WtFudgE
  • 5,080
  • 7
  • 47
  • 59
0

you can use ng-keydown , ng-keyup , ng-press such as this .

to triger a function :

   <input type="text" ng-keypress="function()"/>

or if you have one condion such as when he press escape (27 is the key code for escape)

 <form ng-keydown=" event.which=== 27?cancelSplit():0">
....
</form>
Eassa Nassar
  • 700
  • 9
  • 15
0

I think using document.bind is a bit more elegant

constructor($scope, $document) {
  var that = this;
  $document.bind("keydown", function(event) {
    $scope.$apply(function(){
      that.handleKeyDown(event);
    });
  });
}

To get document to the controller constructor:

controller: ['$scope', '$document', MyCtrl]
FreshPow
  • 6,782
  • 1
  • 15
  • 17
0
(function(angular) {
  'use strict';
angular.module('dragModule', [])
  .directive('myDraggable', ['$document', function($document) {
    return {
      link: function(scope, element, attr) {
         element.bind("keydown keypress", function (event) {
           console.log('keydown keypress', event.which);
            if(event.which === 13) {
                event.preventDefault();
            }
        });
      }
    };
  }]);
})(window.angular);
Mukundhan
  • 3,284
  • 23
  • 36
0

All you need to do to get the event is the following:

console.log(angular.element(event.which));

A directive can do it, but that is not how you do it.

Konkret
  • 991
  • 9
  • 14