Question

I'm building an app in Angular and I'd like to have keypress events. However, I'd prefer not to litter my code with a keypress here and a keypress there, but rather to put all keypress events into a single factory (or service) and then import this factory into my controllers to use.

I HOPE that doing things this way will make it easier for me to manage the keypress events and make sure I don't have conflicts (two events tied to the same keypresses) or something like that.

Does anybody have any suggestions on how to manage this?

I'm using angular-ui-keypress.

As an example of how I'm hoping to use keypress events.

The user may have multiple tabs open and hits 'cmd+s' to save the files. Rather than a 'save' method being triggered on each of the open files, I've got an OpenFilesFactory, the keypress would map to the OpenFilesFactory.saveFiles method.

Am I going about this all wrong? Is there a reason not to tie keyboard shortcuts to a factory rather than in a controller?

Was it helpful?

Solution

What I ended up doing worked surprisingly well, and I'll opensource it as a module after a bit more work.

I created a directive, which binds to the keypress events on $document

angular.module('keypress', []).directive('keypressEvents', 
  function($document, $rootScope) {
    return {
      restrict: 'A',
      link: function() {
        $document.bind('keypress', function(e) {
           $rootScope.$broadcast('keypress',e , String.fromCharCode(e.which));
        });
     }
   }
})

I then created a second directive for watching for keypresses on specific elements, basically giving the element a focus for key events.

angular.module('focus', []).directive('onFocus',
  function() {
    return {
      restrict: 'C',
      link: function(scope) {
       scope.$on('keypress',function(e,parent_evt,key){
        if(scope.keyBindings[key]){
          scope.keyBindings[key](parent_evt, e); 
                          // params reversed so user goes up the chain
        }
       });
     }
   }
 });

In any controller where you want to use keyboard shortcuts, add a keybindings object

function keyedS(key, parent_evt, evt){
      // key is the key that was pressed
      // parent_evt is the keypress event
      // evt is the focused element object
}
$scope.keyBindings = {
    's': keyedS
}

Feedback?

I've actually put this together with multiple keybindings, so if the user selects 'ctrl-shift-s', that is what gets passed along the chain. Though I'm still struggling to find a really good way of getting all the press events. Eg. Tab doesn't work at the moment.

OTHER TIPS

I get what you mean by having it be a separate resource. To me, it seems to go against thinking in Angular, as events really should be "controlled." If you want to have all keypress (or click) events centralized, maybe a switch/case is in order:

$scope.keypressHandler = function () {
switch ($event.keyCode)
{
case 13:
$scope.someEnterKeyFunction();
break;
default:
$scope.someDefaultFunction();
break;
}
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top