2

I need to redirect the user to a specific route when he/she presses a specific key from the keyboard. My question is:

In the light of separation of concerns and AngularJS best practices, should this code remain on a directive or on a service?

I'm aware that directives should be used to manipulate DOM. So, with that in mind, I created the service below:

myApp.factory("KeyPressEvents", ['$rootScope', '$document', '$location', function($rootScope, $document, $location){
    return $document.bind("keypress", function(event){
        if(event.charCode==112){
            $rootScope.$apply(function(){
                $location.path('/route2');
            });
        }
    });
}]);

In the code above, the user is redirected to '/route2' whenever he presses P on the keyboard.

On the other hand, researching on stackoverflow, I realized that some answers recommend the use directives to do almost the same thing:

How to use a keypress event in AngularJS?

Binding keyboard events in AngularJS

And that is why I still don't quite get it. Any thoughts on that issue? Thanks!

Community
  • 1
  • 1
Brunno Vodola Martins
  • 1,582
  • 2
  • 15
  • 17
  • 1
    Since you're picking up keypresses globally, you might want to put it in `myApp.config()` or `myApp.run()` – Daniel Weiner Jan 19 '15 at 23:58
  • 1
    In both links you posted, they used a custom directive because [ng-keypress](https://code.angularjs.org/1.2.28/docs/api/ng/directive/ngKeypress) wasn't available until AngularJS v1.2. Even then, someone else proposed the use of AngularUI. I don't think you should either use a custom directive or service but bind the ng-keypress to some scope method instead. – Roberto Linares Jan 19 '15 at 23:58
  • @DanielWeiner, how can I put the factory in myApp.run()? I think that's a good aproach, since I want things to be available globally. But I just coudn't make it work. – Brunno Vodola Martins Feb 11 '15 at 20:09
  • 1
    You don't need a factory. You could just call $document.bind inside of myApp.run(). – Daniel Weiner Feb 11 '15 at 20:13
  • Thanks for the clarification, @DanielWeiner. It was easier than I thought! – Brunno Vodola Martins Feb 12 '15 at 22:36

2 Answers2

0

IMO, a directive isn't just limited to DOM manipulation, but also works well for UI interaction. I did something similar that registered a scanner (which, as far as my application was concerned, just "types" a few characters followed by a product code). I stuck the directive on the html tag (keep in mind, the ng-app needs to be on the html tag too for this to work). Though you could probably put the directive on a text input too - in my situation it needed to be on the body.

<html ng-app="myApp" scanner>

Essentially this directive listens for the caret character, if it detects it, it will use the ScannerService to then perform a redirect accordingly.

  myApp.directive('scanner', ["$state", "ScannerService", function ($state, ScannerService){
    return {
      restrict: 'A',
      link: function (scope, elem) {

        elem.bind('keypress', function (e) {
          if (e.which === 94) { // ^
            barcodeListen = true;
          }

          if (barcodeListen === true) {
            if (e.which === 13) { // new-line
              ScannerService.processBarcode(barcodeText);
              barcodeListen = false;
            }
            e.preventDefault(); // don't print character
          }
        });

      }
    };
  }]);
Joao
  • 2,696
  • 2
  • 25
  • 35
0

As I wanted the shortcuts to be application-wide, I inserted the code inside app.run, as suggested by @DanielWeiner 's comment. So, I ended up with this:

app.run(['$rootScope', '$document', '$location',
    function($rootScope, $document, $location){
        $document.bind("keypress", function(event) {
            if($('input:focus').length == 0) {
                // If we press the 'j' key, goes to /route2
                if(event.charCode==112){
                    $rootScope.$apply(function(){
                        $location.path('/route2');
                    });
                }
            }
        });
    }
]);

Thank you for the answers and comments.

Brunno Vodola Martins
  • 1,582
  • 2
  • 15
  • 17