How to watch for a keypress combination in Angular

2019-03-15 19:50发布

This question already has an answer here:

I'm trying to get my controller to watch for a combination of keys. For argument's sake, let's say: up up down down left right left right b a. How can I get angular to look out for these regardless of where in the page the user currently is?

7条回答
Emotional °昔
2楼-- · 2019-03-15 20:19

Here's my take on it:

var app = angular.module('contra', []);
app.directive('code', function () {
    function codeState() {
        this.currentState = 0;
        this.keys = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65];
        this.keyPressed = function (key) {
            if (this.keys[this.currentState] == key) {
                this.currentState++;
                if (this.currentState == this.keys.length) {
                    this.currentState = 0;
                    return true;
                }
            } else {
                this.currentState = 0;
            }
            return false;
        };
    };
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var cs = new codeState();
            scope.isValid = "NO";
            element.bind("keydown", function (event) {
                scope.$apply(function () {
                    if (cs.keyPressed(event.which)) {
                        scope.isValid = "YES";
                        console.log("CODE ENTERED");
                    } else {
                        scope.isValid = "NO";
                    }
                });
            });
        }
    }
});

What's different about this is it's a directive so if you attach this on the body, it'll apply to the whole page. This also allows for entering the code multiple times.

Plunkr:

http://plnkr.co/edit/tISvsjYKYDrSvA8pu2St

查看更多
手持菜刀,她持情操
3楼-- · 2019-03-15 20:26

If you are trying 'ctrl+s' or 'commond+s' ( change the commondKey ) to do save, maybe can use like it :

directive :

(function () {

  'use strict';
  var lastKey = 0;
  //var commondKey = 17;
  var commondKey = 91;
  angular
    .module('xinshu')
    .directive('saveEnter', function () {
      return function (scope, element, attrs) {
        element.bind("keydown", function (event) {
          if (event.which != commondKey && event.which != 83) {
            lastKey = 0;
          }
          if (lastKey == commondKey && event.which == 83) {
            scope.$apply(function () {
              scope.$eval(attrs.saveEnter);
            });
            event.preventDefault();
          }
          lastKey = event.which;
        });
      };
    });
})();

element :

<input id="title" save-enter="vm.saveTitle()"/>

You can rename the saveEnter in directive, with change the save-enter in html.

The 'vm.saveTitle()' is the fuc your want to do.

查看更多
SAY GOODBYE
4楼-- · 2019-03-15 20:27

Looks like you can use the ng-keydown to do this.

Here is a working plunker.

For this sample, I just bound ng-keydown to <body>. Works pretty well to catch all the keyboard events globally.

As @charlietfl points out, ng-keydown registers a lot of keyboard events so to make this usable would be a lot of work. For example, if you were trying to listen for a combination (like ctrl + r), then the ctrl key will register many times.

JS:

var myApp = angular.module('myApp', []);

myApp.controller('Ctrl', function($scope) {


    $scope.keyBuffer = [];

    function arrays_equal(a,b) { return !(a<b || b<a); }

    $scope.down = function(e) {

      $scope.keyBuffer.push(e.keyCode);

      var upUp = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65];
      if (arrays_equal(upUp, $scope.keyBuffer)) {

        alert('thats it!');
      }
    };

  });

HTML:

<body ng-controller="Ctrl" ng-keydown="down($event)">
查看更多
叼着烟拽天下
5楼-- · 2019-03-15 20:28

I'm using a different way to do it.

$scope.keyboard = {
  buffer: [],
  detectCombination: function() {
    var codes = {};

    this.buffer.forEach(function(code) {
      codes['key_' + code] = 1;
    });

    if ((codes.key_91 || codes.key_93) && codes.key_8) {
      // I'm looking for 'command + delete'
    }
  },
  keydown: function($event) {
    this.buffer.push($event.keyCode);
    this.detectCombination();
  },
  keyup: function($event, week) {
    this.buffer = [];
  }
};
查看更多
甜甜的少女心
6楼-- · 2019-03-15 20:29

Check out this plunker. I've implemented a simple '2 UP keystrokes in a row' scenario.

You can do it in plain jQuery and communicate the event with a $rootScope.$broadcast.

Register the jQuery code in and Angular run callback (guarantees that angular has already bootstraped):

app.run(function($rootScope) {
  var upHitOnce = false;
  $(document).keyup(function(event) {
    if (event.which == 38) {
      if (upHitOnce) {
        $rootScope.$broadcast('DoubleUpFired');
        $rootScope.$apply();
        upHitOnce = false;
      } else {
        upHitOnce = true;
      }
    } else {
      upHitOnce = false;
    }
  });
});

and then any controller can listen to this event like:

$scope.$on('DoubleUpFired', function() {
    $scope.fired = true;
});

Binding an ng-keydown action callback to body is ok, but has a small disadvantage. It fires a $digest on every keystroke. What you really want is a $digest only when the sequence has been entered when you somehow need to update the UI.

EDIT

See comments on how to remove actual jQuery dependency.

查看更多
做自己的国王
7楼-- · 2019-03-15 20:43

Detecting Backspace-Key (Mac) and Del-Key (PC):

<body ng-controller="Ctrl" ng-keydown="keyDown($event)">..<body>

$scope.keyDown = function(value){
    if(value.keyCode == 46 || value.keyCode == 8) {
        //alert('Delete Key Pressed');
    }
};
查看更多
登录 后发表回答