I suppose that I should use directive, but it seems strange to add directive to body, but listen events on document.
What is a proper way to do this?
UPDATE:
As a Directive
This is essentially how it is done in the Angular documentation code, i.e. pressing / to start searching.
angular
.module("app", [])
.directive("keyboard", keyboard);
function keyboard($document) {
return {
link: function(scope, element, attrs) {
$document.on("keydown", function(event) {
// if keycode...
event.stopPropagation();
event.preventDefault();
scope.$apply(function() {
// update scope...
});
}
};
}
Plunk using a keyboard directive
http://plnkr.co/edit/C61Gnn?p=preview
As a Service
Converting that directive into a service is real easy. The only real difference is that the scope is not exposed on the service. To trigger a digest, you can bring in the $rootScope or use a $timeout.
function Keyboard($document, $timeout, keyCodes) {
var _this = this;
this.keyHandlers = {};
$document.on("keydown", function(event) {
var keyDown = _this.keyHandlers[event.keyCode];
if (keyDown) {
event.preventDefault();
$timeout(function() {
keyDown.callback();
});
}
});
this.on = function(keyName, callback) {
var keyCode = keyCodes[keyName];
this.keyHandlers[keyCode] = { callback: callback };
return this;
};
}
You can now register callbacks in your controller using the keyboard.on() method.
function MainController(keyboard) {
keyboard
.on("ENTER", function() { // do something... })
.on("DELETE", function() { // do something... })
.on("SHIFT", function() { // do something... })
.on("INSERT", function() { // do something... });
}
Alternate version of Plunk using a service
http://plnkr.co/edit/z9edu5?p=preview