Ich nehme an, ich sollte die Direktive verwenden, aber es scheint seltsam, dem Body eine Direktive hinzuzufügen, aber Ereignisse im Dokument anzuhören.
Was ist ein richtiger Weg, um dies zu tun?
UPDATE: Gefunden AngularJS UI und sah ihre Realisierung keypress Richtlinie.
javascript
angularjs
ValeriiVasin
quelle
quelle
$document.bind('keypress')
Antworten:
So habe ich das mit jQuery gemacht - ich denke, es gibt einen besseren Weg.
var app = angular.module('angularjs-starter', []); app.directive('shortcut', function() { return { restrict: 'E', replace: true, scope: true, link: function postLink(scope, iElement, iAttrs){ jQuery(document).on('keypress', function(e){ scope.$apply(scope.keyPressed(e)); }); } }; }); app.controller('MainCtrl', function($scope) { $scope.name = 'World'; $scope.keyCode = ""; $scope.keyPressed = function(e) { $scope.keyCode = e.which; }; });
<body ng-controller="MainCtrl"> <shortcut></shortcut> <h1>View keys pressed</h1> {{keyCode}} </body>
Plunker-Demo
quelle
Ich würde sagen, ein geeigneterer Weg (oder "Winkelweg") wäre, ihn einer Richtlinie hinzuzufügen. Hier ist eine einfache Möglichkeit, um loszulegen (fügen Sie einfach ein
keypress-events
Attribut hinzu<body>
):angular.module('myDirectives', []).directive('keypressEvents', [ '$document', '$rootScope', function($document, $rootScope) { return { restrict: 'A', link: function() { $document.bind('keypress', function(e) { console.log('Got keypress:', e.which); $rootScope.$broadcast('keypress', e); $rootScope.$broadcast('keypress:' + e.which, e); }); } }; } ]);
In Ihrer Direktive können Sie dann einfach so etwas tun:
module.directive('myDirective', [ function() { return { restrict: 'E', link: function(scope, el, attrs) { scope.keyPressed = 'no press :('; // For listening to a keypress event with a specific code scope.$on('keypress:13', function(onEvent, keypressEvent) { scope.keyPressed = 'Enter'; }); // For listening to all keypress events scope.$on('keypress', function(onEvent, keypressEvent) { if (keypress.which === 120) { scope.keyPressed = 'x'; } else { scope.keyPressed = 'Keycode: ' + keypressEvent.which; } }); }, template: '<h1>{{keyPressed}}</h1>' }; } ]);
quelle
Escape
Schlüssel?Verwendung
$document.bind
:function FooCtrl($scope, $document) { ... $document.bind("keypress", function(event) { console.debug(event) }); ... }
quelle
$event
über eine Funktion an den Controller zu übergeben, der andere darin, das Ereignis direkt im Controller zu binden. Die Controller-Methode scheint weniger Code und das gleiche Ergebnis. Gibt es einen Grund, eine Methode der anderen vorzuziehen?var that = this; $document.bind("keydown", function(event) { $scope.$apply(function(){ that.handleKeyDown(event); });
Ich kann noch nicht dafür bürgen, aber ich habe angefangen, mir AngularHotkeys.js anzuschauen:
http://chieffancypants.github.io/angular-hotkeys/
Wird mit weiteren Informationen aktualisiert, sobald ich meine Zähne drin habe.
Update 1: Oh, es gibt ein Nuget-Paket: Angular-Hotkeys
Update 2: eigentlich sehr einfach zu bedienen, richten Sie Ihre Bindung entweder in Ihrer Route oder wie ich in Ihrem Controller ein:
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);
quelle
Hier ist ein Beispiel für einen AngularJS-Dienst für Tastaturkürzel: http://jsfiddle.net/firehist/nzUBg/
Es kann dann folgendermaßen verwendet werden:
function MyController($scope, $timeout, keyboardManager) { // Bind ctrl+shift+d keyboardManager.bind('ctrl+shift+d', function() { console.log('Callback ctrl+shift+d'); }); }
Update: Ich verwende jetzt stattdessen Winkel-Hotkeys .
quelle
Als Richtlinie
Dies geschieht im Wesentlichen im Angular-Dokumentationscode, dh Drücken Sie
/
, um die Suche zu starten.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 mit einer Tastaturanweisung
http://plnkr.co/edit/C61Gnn?p=preview
Als Dienstleistung
Die Umwandlung dieser Richtlinie in einen Dienst ist sehr einfach. Der einzige wirkliche Unterschied besteht darin, dass der Bereich für den Dienst nicht verfügbar ist. Um eine Verdauung auszulösen, können Sie die einbringen
$rootScope
oder eine verwenden$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; }; }
Mit der
keyboard.on()
Methode können Sie jetzt Rückrufe in Ihrem Controller registrieren .function MainController(keyboard) { keyboard .on("ENTER", function() { // do something... }) .on("DELETE", function() { // do something... }) .on("SHIFT", function() { // do something... }) .on("INSERT", function() { // do something... }); }
Alternative Version von Plunk über einen Dienst
http://plnkr.co/edit/z9edu5?p=preview
quelle
Die etwas kürzere Antwort ist nur die Lösung 3 unten. Wenn Sie mehr Optionen wissen möchten, können Sie das Ganze lesen.
Ich stimme jmagnusson zu. Aber ich glaube, es gibt eine sauberere Lösung. Anstatt die Schlüssel mit Funktionen in der Direktive zu binden, sollten Sie sie einfach in HTML binden können, wie beim Definieren einer Konfigurationsdatei, und die Hotkeys sollten kontextbezogen sein.
Unten finden Sie eine Version, die Mausefalle mit einer benutzerdefinierten Direktive verwendet. (Ich war nicht der Autor dieser Geige.)
var app = angular.module('keyExample', []); app.directive('keybinding', function () { return { restrict: 'E', scope: { invoke: '&' }, link: function (scope, el, attr) { Mousetrap.bind(attr.on, scope.invoke); } }; }); app.controller('RootController', function ($scope) { $scope.gotoInbox = function () { alert('Goto Inbox'); }; }); app.controller('ChildController', function ($scope) { $scope.gotoLabel = function (label) { alert('Goto Label: ' + label); }; });
Sie müssen mousetrap.js einschließen und verwenden es wie folgt:
<div ng-app="keyExample"> <div ng-controller="RootController"> <keybinding on="g i" invoke="gotoInbox()" /> <div ng-controller="ChildController"> <keybinding on="g l" invoke="gotoLabel('Sent')" /> </div> </div> <div>Click in here to gain focus and then try the following key strokes</div> <ul> <li>"g i" to show a "Goto Inbox" alert</li> <li>"g l" to show a "Goto Label" alert</li> </ul> </div>
http://jsfiddle.net/BM2gG/3/
Für die Lösung müssen Sie mousetrap.js einbinden, eine Bibliothek, mit der Sie Hotkeys definieren können.
Wenn Sie die Mühe vermeiden möchten, Ihre eigene benutzerdefinierte Direktive zu entwickeln, können Sie diese Bibliothek lesen:
https://github.com/drahak/angular-hotkeys
Und das
https://github.com/chieffancypants/angular-hotkeys
Die zweite bietet etwas mehr Funktionen und Flexibilität, dh automatisch generierte Hotkey-Spickzettel für Ihre App.
Update : Lösung 3 ist nicht mehr in Angular UI verfügbar.
Abgesehen von den oben genannten Lösungen gibt es eine weitere Implementierung, die vom Angularui-Team durchgeführt wird. Der Nachteil ist jedoch, dass die Lösung von JQuery lib abhängt, was in der Winkel-Community nicht der Trend ist. (Die Angular-Community versucht, nur das mit AngularJs gelieferte jqLite zu verwenden, um überhöhte Abhängigkeiten zu vermeiden.) Hier ist der Link
http://angular-ui.github.io/ui-utils/#/keypress
Die Verwendung ist wie folgt:
Verwenden Sie in Ihrem HTML-Code das Attribut ui-keydown, um Schlüssel und Funktionen zu binden.
<div class="modal-inner" ui-keydown="{ esc: 'cancelModal()', tab: 'tabWatch($event)', enter: 'initOrSetModel()' }">
Fügen Sie in Ihrer Direktive diese Funktionen in Ihren Geltungsbereich ein.
app.directive('yourDirective', function () { return { restrict: 'E', templateUrl: 'your-html-template-address.html' link: function(){ scope.cancelModal() = function (){ console.log('cancel modal'); }; scope.tabWatch() = function (){ console.log('tabWatch'); }; scope.initOrSetModel() = function (){ console.log('init or set model'); }; } }; });
Nachdem ich mit allen Lösungen herumgespielt habe, würde ich die empfehlen, die vom Angular UI-Team implementiert wird, Lösung 3, die viele kleine seltsame Probleme vermeidet, auf die ich gestoßen bin.
quelle
Ich habe einen Dienst für Verknüpfungen erstellt.
Es sieht aus wie:
angular.module('myApp.services.shortcuts', []) .factory('Shortcuts', function($rootScope) { var service = {}; service.trigger = function(keycode, items, element) { // write the shortcuts logic here... } return service; })
Und ich habe es in einen Controller injiziert:
angular.module('myApp.controllers.mainCtrl', []) .controller('mainCtrl', function($scope, $element, $document, Shortcuts) { // whatever blah blah $document.on('keydown', function(){ // skip if it focused in input tag if(event.target.tagName !== "INPUT") { Shortcuts.trigger(event.which, $scope.items, $element); } }) })
Es funktioniert, aber Sie werden vielleicht bemerken, dass ich $ element und $ document in den Controller einspeise.
Es ist eine schlechte Controller-Praxis und verstößt gegen die Konvention "Nie auf $ zugreifen" in der Controller-Konvention.
Ich sollte es in die Direktive setzen und dann 'ngKeydown' und $ event verwenden, um den Dienst auszulösen.
Aber ich denke, der Service ist in Ordnung und ich werde den Controller früher überarbeiten.
Aktualisiert:
Es scheint, dass 'ng-keydown' nur in Eingabe-Tags funktioniert.
Also schreibe ich einfach eine Direktive und füge $ document ein:
angular.module('myApp.controllers.mainCtrl', []) .directive('keyboard', function($scope, $document, Shortcuts) { // whatever blah blah return { link: function(scope, element, attrs) { scope.items = ....;// something not important $document.on('keydown', function(){ // skip if it focused in input tag if(event.target.tagName !== "INPUT") { Shortcuts.trigger(event.which, scope.items, element); } }) } } })
Es ist besser.
quelle
Überprüfen Sie dieses Beispiel von den Jungs behid ng-newsletter.com; Schauen Sie sich das Tutorial zum Erstellen eines 2048-Spiels an. Es enthält einen netten Code, der einen Dienst für Tastaturereignisse verwendet.
quelle
Im Folgenden können Sie Ihre gesamte Verknüpfungslogik in Ihren Controller schreiben, und die Direktive kümmert sich um alles andere.
Richtlinie
.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()); } }; }])
Regler
$scope.keyUp = function(key) { // H. if (72 == key.keyCode) $scope.toggleHelp(); };
Html
<div shortcuts="keyUp"> <!-- Stuff --> </div>
quelle
Sie können diese Bibliothek ausprobieren. Sie hat es sehr einfach gemacht, Hotkeys zu verwalten. Sie bindet und bindet automatisch Schlüssel, wenn Sie durch die App navigieren
eckige Hotkeys
quelle
Ich weiß nicht, ob es ein wirklich eckiger Weg ist, aber was ich getan habe
$(document).on('keydown', function(e) { $('.button[data-key=' + String.fromCharCode(e.which) + ']').click(); }); <div class="button" data-key="1" ng-click="clickHandler($event)"> ButtonLabel </div>
quelle