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:
Check this example from the guys behid ng-newsletter.com; check their tutorial on creating a 2048 game, it has some nice code using a service for keyboard events.
The following let's you write all your shortcut logic in your controller and the directive will take care of everything else.
Directive
.directive('shortcuts', ['$document', '$rootScope', function($document, $rootScope) {
$rootScope.shortcuts = [];
$document.on('keydown', function(e) {
// Skip if it focused in input tag.
if (event.target.tagName !== "INPUT") {
$rootScope.shortcuts.forEach(function(eventHandler) {
// Skip if it focused in input tag.
if (event.target.tagName !== 'INPUT' && eventHandler)
eventHandler(e.originalEvent, e)
});
}
})
return {
restrict: 'A',
scope: {
'shortcuts': '&'
},
link: function(scope, element, attrs) {
$rootScope.shortcuts.push(scope.shortcuts());
}
};
}])
Controller
$scope.keyUp = function(key) {
// H.
if (72 == key.keyCode)
$scope.toggleHelp();
};
Html
<div shortcuts="keyUp">
<!-- Stuff -->
</div>
I can't vouch for it just yet but I've started taking a look at AngularHotkeys.js:
http://chieffancypants.github.io/angular-hotkeys/
Will update with more info once I've got my teeth into it.
Update 1: Oh there's a nuget package: angular-hotkeys
Update 2: actually very easy to use, just set up your binding either in your route or as I'm doing, in your controller:
hotkeys.add('n', 'Create a new Category', $scope.showCreateView);
hotkeys.add('e', 'Edit the selected Category', $scope.showEditView);
hotkeys.add('d', 'Delete the selected Category', $scope.remove);
Here's an example of an AngularJS service for keyboard shortcuts: http://jsfiddle.net/firehist/nzUBg/
It can then be used like this:
function MyController($scope, $timeout, keyboardManager) {
// Bind ctrl+shift+d
keyboardManager.bind('ctrl+shift+d', function() {
console.log('Callback ctrl+shift+d');
});
}
Update: I'm now using angular-hotkeys instead.
you can try this library it made it very easy to manage hot keys, it automatically binds and unbinds keys as you navigate the app
angular-hotkeys
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