AngularJS Directive Labs: ngEnterKey, ngKeyCode

If you have used AngularJS and needed to use ng-keypress, you will find that it can become tedious when you have to add logic into your controller functions to match key codes to your desired functionality.

<div ng-controller="MainCtrl"> 
<input type="text"
ng-keypress="checkIfEnterKeyWasPressed($event)"
/>
</div>
app.module("myApp").controller("MainCtrl", ["$scope", MainCtrl]); function MainCtrl($scope){
$scope.checkIfEnterKeyWasPressed = function($event){
var keyCode = $event.which || $event.keyCode;
if (keyCode === 13) {
// Do that thing you finally wanted to do
}
};
}

But if you are only needing to bind one keycode, let’s write a directive. Inside our directive we can bind a keypress or keydown event and bind it to our directive element:

angular.module("myApp").directive('dlEnterKey', function() { 
return function(scope, element, attrs) {
element.bind("keydown keypress", function(event) {
var keyCode = event.which || event.keyCode;

// If enter key is pressed
if (keyCode === 13) {
scope.$apply(function() {
// Evaluate the expression
scope.$eval(attrs.dlEnterKey);
});
event.preventDefault();
}
});
};
});

This way we can keep our logic clean in our controller, and have some more clarity in the DOM about what the directive is trying to accomplish.

<div class="form"> 
<input type="text" dl-enter-key="closeModalWindow();" />
</div>

But can we get fancier? I think we can. What if we wanted to specify a key code and expression?

I played around with this and whipped up dlKeyCode:

angular.module("myApp").directive('dlKeyCode', dlKeyCode); function dlKeyCode() { 
return {
restrict: 'A',
link: function($scope, $element, $attrs) {
$element.bind("keypress", function(event) {
var keyCode = event.which || event.keyCode;
if (keyCode == $attrs.code) {
$scope.$apply(function() {
$scope.$eval($attrs.dlKeyCode, {$event: event});
});
}
});
}
};
}

As I was working on this I did notice that because we are grabbing the key code from the $attrs, that I had to use == instead of === to match to the keycode expression. Using $scope.$eval($attrs.dlKeyCode, {$event: event}); lets us also pass through the $event object to the expression string, that way if you wanted to check for modifiers or call preventDefault(), then you can do so!

Overall this directive/example gives you more flexibility than making 5–10 directives for specific code, or clutting your logic with additional keycode checking functions.

<div class="form"> 
<input type="text" code="13" dl-key-code="closeModalWindow();" />
<input type="text" code="24" dl-key-code="submitInformation();" /> </div>

As you know this is called Directive Labs so the experiments will keep brewing. If you have any suggestions, improvements, or ideas for directives like this, feel free to let me know!!

You can take a look at the feature request for this directive found on AngularJS’s GitHub!!

UPDATE: Thanks to a great note by @kadimi, it is important to be using non-ng specific nameing prefixes for your directives! I’ve updated my examples here to use “dl” for “Directive Labs”, but feel free to use whatever prefix you would like in your own implementation!!!!

Originally published at codepen.io.

--

--

Sean T. Larkin
Mutual of Omaha - Digital Experience and Design Team

@Webpack Core team & AngularCLI team. Program Manager @Microsoft @EdgeDevTools. Web Performance, JavaScripter, Woodworker, 🐓 Farmer, and Gardener!