Comment utiliser un événement de pression de touche dans AngularJS?


410

Je veux attraper l'événement de la touche Entrée dans la zone de texte ci-dessous. Pour être plus clair, j'utilise un ng-repeatpour remplir le corps. Voici le HTML:

<td><input type="number" id="closeqty{{$index}}" class="pagination-right closefield" 
    data-ng-model="closeqtymodel" data-ng-change="change($index)" required placeholder="{{item.closeMeasure}}" /></td>

Voici mon module:

angular.module('components', ['ngResource']);

J'utilise une ressource pour remplir la table et mon code de contrôleur est:

function Ajaxy($scope, $resource) {
//controller which has resource to populate the table 
}

1
L'entrée est-elle dans un formulaire?
callmekatootie

1
non .. c'est dans une table !!
Venkata Tata

Réponses:


808

Vous devez ajouter un directive, comme ceci:

Javascript :

app.directive('myEnter', function () {
    return function (scope, element, attrs) {
        element.bind("keydown keypress", function (event) {
            if(event.which === 13) {
                scope.$apply(function (){
                    scope.$eval(attrs.myEnter);
                });

                event.preventDefault();
            }
        });
    };
});

HTML :

<div ng-app="" ng-controller="MainCtrl">
    <input type="text" my-enter="doSomething()">    
</div>

7
@DerekAdair La directive se lie aux événements keydownet keypressde l'élément auquel elle est attribuée. Lorsque l'événement est reçu, l'expression fournie est évaluée dans un $applybloc.
Pete Martin

7
Plus sûr de définir la clé comme ceci: var key = typeof event.which === "undefined" ? event.keyCode : event.which;tant que event.which n'est pas utilisé par tous les navigateurs. Voir les commentaires ici: stackoverflow.com/a/4471635/2547632
Gabriel

3
J'ajouterais également keyupdans le test de liaison
user1713964

59
notez également que l'utilisation du préfixe ng n'est pas recommandée, car cela pourrait entrer en conflit avec les futures directives ng- *. Utilisez le vôtre à la place
Marius Balčytis

3
N'oubliez pas de détruire vos liaisons: scope. $ On ('$ destroy', function () {element.unbind ('keydown');})
nawlbergs

345

Une alternative est d'utiliser la directive standard ng-keypress="myFunct($event)"

Ensuite, dans votre contrôleur, vous pouvez avoir:

...

$scope.myFunct = function(keyEvent) {
  if (keyEvent.which === 13)
    alert('I am an alert');
}

...

18
Pour gagner du temps, ng-keypressil ne semble pas que angular 1.0.x, ui-keypress(avec une sémantique d'appel légèrement différente) soit disponible: angular-ui.github.io/ui-utils
Cebjyre

1
Je pense que le commentaire ci-dessus visait une réponse différente. (Juste pour référence.)
Cornelius

Martin, c'est en fait la fonction d'un contrôleur: gérer les événements de l'interface utilisateur.
Trevor de Koekkoek

5
Mieux encore, utilisez ngKeypress et passez l'événement $ à un filtre personnalisé.
Martin

7
Meilleure réponse +1. Pourquoi devrais-je créer ma propre directive, s'il y en a une, déjà incluse dans Angular?
bFunc

179

Mon approche la plus simple utilisant une directive build juste angulaire:

ng-keypress, ng-keydownou ng-keyup.

Habituellement, nous voulons ajouter la prise en charge du clavier pour quelque chose qui est déjà géré par ng-click.

par exemple:

<a ng-click="action()">action</a>

Maintenant, ajoutons la prise en charge du clavier.

déclenchement par touche entrée:

<a ng-click="action()" 
   ng-keydown="$event.keyCode === 13 && action()">action</a>

par touche espace:

<a ng-click="action()" 
   ng-keydown="$event.keyCode === 32 && action()">action</a>

par espace ou touche entrée:

<a ng-click="action()" 
   ng-keydown="($event.keyCode === 13 || $event.keyCode === 32) && action()">action</a>

si vous êtes dans un navigateur moderne

<a ng-click="action()" 
   ng-keydown="[13, 32].includes($event.keyCode) && action()">action</a>

En savoir plus sur keyCode:
keyCode est obsolète mais bien pris en charge, vous pouvez utiliser $ evevt.key dans le navigateur pris en charge à la place.
Voir plus dans https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key


1
le secret est le conditionnel avant la méthode à exécuter $ event.which === 13 && action () - merci!
user12121234

1
'$ event.which' ne fonctionne pas pour moi, mais j'ai trouvé '$ event.keyCode' qui fonctionne.
Karl Adler

event.which est indéfini dans IE <9 lors de keydown et keyup.
Eric Chen

2
"vieux navigateurs comme IE9" ..
je n'aurais

1
Pourquoi personne n'a-t-il mis à jour les extraits de code ici pour utiliser $ event.keyCode alors? Je l'éditerais moi-même, mais je ne suis pas en mesure de le faire pour une raison quelconque.
Nathan Hazzard


19

Voici ce que j'ai compris lorsque je construisais une application avec une exigence similaire, cela ne nécessite pas d'écrire une directive et il est relativement simple de dire ce qu'elle fait:

<input type="text" ng-keypress="($event.charCode==13)?myFunction():return" placeholder="Will Submit on Enter">

3
Simple et efficace.
Xplouder

15

Vous pouvez utiliser ng-keydown = "myFunction ($ event)" comme attribut.

<input ng-keydown="myFunction($event)" type="number">

myFunction(event) {
    if(event.keyCode == 13) {   // '13' is the key code for enter
        // do what you want to do when 'enter' is pressed :)
    }
}

5

html

<textarea id="messageTxt" 
    rows="5" 
    placeholder="Escriba su mensaje" 
    ng-keypress="keyPressed($event)" 
    ng-model="smsData.mensaje">
</textarea>

controller.js

$scope.keyPressed = function (keyEvent) {
    if (keyEvent.keyCode == 13) {
        alert('presiono enter');
        console.log('presiono enter');
    }
};

3

Vous pouvez également l'appliquer à un contrôleur sur un élément parent. Cet exemple peut être utilisé pour mettre une ligne en surbrillance dans un tableau en appuyant sur les touches fléchées haut / bas.

app.controller('tableCtrl', [ '$scope', '$element', function($scope, $element) {
  $scope.index = 0; // row index
  $scope.data = []; // array of items
  $scope.keypress = function(offset) {
    console.log('keypress', offset);
    var i = $scope.index + offset;
    if (i < 0) { i = $scope.data.length - 1; }
    if (i >= $scope.data.length) { i = 0; }
  };
  $element.bind("keydown keypress", function (event) {
    console.log('keypress', event, event.which);
    if(event.which === 38) { // up
      $scope.keypress(-1);
    } else if (event.which === 40) { // down
      $scope.keypress(1);
    } else {
      return;
    }
    event.preventDefault();
  });
}]);


<table class="table table-striped" ng-controller="tableCtrl">
<thead>
    <tr>
        <th ng-repeat="(key, value) in data[0]">{{key}}</th>
    </tr>
</thead>
<tbody>
    <tr ng-repeat="row in data track by $index" ng-click="draw($index)" ng-class="$index == index ? 'info' : ''">
        <td ng-repeat="(key, value) in row">{{value}}</td>
    </tr>
</tbody>
</table>


3

En essayant

ng-keypress="console.log($event)"
ng-keypress="alert(123)"

n'a rien fait pour moi.

Strangley l'exemple à https://docs.angularjs.org/api/ng/directive/ngKeypress , qui fait ng-keypress = "count = count + 1", fonctionne.

J'ai trouvé une autre solution, en appuyant sur Entrée, appelez le ng-clic du bouton.

<input ng-model="..." onkeypress="if (event.which==13) document.getElementById('button').click()"/>
<button id="button" ng-click="doSomething()">Done</button>

ng-keypress="console.log('foo')"n'a pas fonctionné pour moi non plus, mais si vous le faites ng-keypress="fooMethod()"et dans votre contrôleur $scope.fooMethod = function() { console.log('fooMethod called'); }fonctionne.
GraehamF

3
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
Informe your name:<input type="text" ng-model="pergunta" ng-keypress="pressionou_enter($event)" ></input> 
<button ng-click="chamar()">submit</button>
<h1>{{resposta}}</h1> 
</div>
<script>
var app = angular.module('myApp', []);
//create a service mitsuplik
app.service('mitsuplik', function() {
    this.myFunc = function (parametro) {
        var tmp = ""; 
        for (var x=0;x<parametro.length;x++)
            {
            tmp = parametro.substring(x,x+1) + tmp;
            } 
        return tmp;
    }
});
//Calling our service
app.controller('myCtrl', function($scope, mitsuplik) { 
  $scope.chamar = function() { 
        $scope.resposta = mitsuplik.myFunc($scope.pergunta); 
    };
  //if mitsuplik press [ENTER], execute too
  $scope.pressionou_enter = function(keyEvent) {
             if (keyEvent.which === 13) 
                { 
                $scope.chamar();
                }

    }
});
</script>
</body>
</html>

2

Ceci est une extension de la réponse d'EpokK.

J'ai eu le même problème d'avoir à appeler une fonction de portée lorsque enter est poussé sur un champ de saisie. Cependant, je voulais également transmettre la valeur du champ de saisie à la fonction spécifiée. Voici ma solution:

app.directive('ltaEnter', function () {
return function (scope, element, attrs) {
    element.bind("keydown keypress", function (event) {
        if(event.which === 13) {
          // Create closure with proper command
          var fn = function(command) {
            var cmd = command;
            return function() {
              scope.$eval(cmd);
            };
          }(attrs.ltaEnter.replace('()', '("'+ event.target.value +'")' ));

          // Apply function
          scope.$apply(fn);

          event.preventDefault();
        }
    });
};

});

L'utilisation en HTML est la suivante:

<input type="text" name="itemname" lta-enter="add()" placeholder="Add item"/>

Félicitations à EpokK pour sa réponse.


<input type="text" name="itemname" ng-model="item.itemname" lta-enter="add(item.itemname)" placeholder="Add item"/>
aycanadal

1

Et ça?:

<form ng-submit="chat.sendMessage()">
    <input type="text" />
    <button type="submit">
</form>

Maintenant, lorsque vous appuyez sur la touche Entrée après avoir écrit quelque chose dans votre entrée, le formulaire sait comment le gérer.


Comment / où est chat.sendMessage()défini
Aaron McMillin

0

Un exemple de code que j'ai fait pour mon projet. Fondamentalement, vous ajoutez des balises à votre entité. Imaginez que vous avez du texte d'entrée, en entrant le nom de la balise, vous obtenez un menu déroulant avec des balises préchargées à choisir, vous naviguez avec des flèches et sélectionnez avec Entrée:

HTML + AngularJS v1.2.0-rc.3

    <div>
        <form ng-submit="addTag(newTag)">
            <input id="newTag" ng-model="newTag" type="text" class="form-control" placeholder="Enter new tag"
                   style="padding-left: 10px; width: 700px; height: 33px; margin-top: 10px; margin-bottom: 3px;" autofocus
                   data-toggle="dropdown"
                   ng-change="preloadTags()"
                   ng-keydown="navigateTags($event)">
            <div ng-show="preloadedTags.length > 0">
                <nav class="dropdown">
                    <div class="dropdown-menu preloadedTagPanel">
                        <div ng-repeat="preloadedTag in preloadedTags"
                             class="preloadedTagItemPanel"
                             ng-class="preloadedTag.activeTag ? 'preloadedTagItemPanelActive' : '' "
                             ng-click="selectTag(preloadedTag)"
                             tabindex="{{ $index }}">
                            <a class="preloadedTagItem"
                               ng-class="preloadedTag.activeTag ? 'preloadedTagItemActive' : '' "
                               ng-click="selectTag(preloadedTag)">{{ preloadedTag.label }}</a>
                        </div>
                    </div>
                </nav>
            </div>
        </form>
    </div>

Controller.js

$scope.preloadTags = function () {
    var newTag = $scope.newTag;
    if (newTag && newTag.trim()) {
        newTag = newTag.trim().toLowerCase();

        $http(
            {
                method: 'GET',
                url: 'api/tag/gettags',
                dataType: 'json',
                contentType: 'application/json',
                mimeType: 'application/json',
                params: {'term': newTag}
            }
        )
            .success(function (result) {
                $scope.preloadedTags = result;
                $scope.preloadedTagsIndex = -1;
            }
        )
            .error(function (data, status, headers, config) {
            }
        );
    } else {
        $scope.preloadedTags = {};
        $scope.preloadedTagsIndex = -1;
    }
};

function checkIndex(index) {
    if (index > $scope.preloadedTags.length - 1) {
        return 0;
    }
    if (index < 0) {
        return $scope.preloadedTags.length - 1;
    }
    return index;
}

function removeAllActiveTags() {
    for (var x = 0; x < $scope.preloadedTags.length; x++) {
        if ($scope.preloadedTags[x].activeTag) {
            $scope.preloadedTags[x].activeTag = false;
        }
    }
}

$scope.navigateTags = function ($event) {
    if (!$scope.newTag || $scope.preloadedTags.length == 0) {
        return;
    }
    if ($event.keyCode == 40) {  // down
        removeAllActiveTags();
        $scope.preloadedTagsIndex = checkIndex($scope.preloadedTagsIndex + 1);
        $scope.preloadedTags[$scope.preloadedTagsIndex].activeTag = true;
    } else if ($event.keyCode == 38) {  // up
        removeAllActiveTags();
        $scope.preloadedTagsIndex = checkIndex($scope.preloadedTagsIndex - 1);
        $scope.preloadedTags[$scope.preloadedTagsIndex].activeTag = true;
    } else if ($event.keyCode == 13) {  // enter
        removeAllActiveTags();
        $scope.selectTag($scope.preloadedTags[$scope.preloadedTagsIndex]);
    }
};

$scope.selectTag = function (preloadedTag) {
    $scope.addTag(preloadedTag.label);
};

CSS + Bootstrap v2.3.2

.preloadedTagPanel {
    background-color: #FFFFFF;
    display: block;
    min-width: 250px;
    max-width: 700px;
    border: 1px solid #666666;
    padding-top: 0;
    border-radius: 0;
}

.preloadedTagItemPanel {
    background-color: #FFFFFF;
    border-bottom: 1px solid #666666;
    cursor: pointer;
}

.preloadedTagItemPanel:hover {
    background-color: #666666;
}

.preloadedTagItemPanelActive {
    background-color: #666666;
}

.preloadedTagItem {
    display: inline-block;
    text-decoration: none;
    margin-left: 5px;
    margin-right: 5px;
    padding-top: 5px;
    padding-bottom: 5px;
    padding-left: 20px;
    padding-right: 10px;
    color: #666666 !important;
    font-size: 11px;
}

.preloadedTagItem:hover {
    background-color: #666666;
}

.preloadedTagItemActive {
    background-color: #666666;
    color: #FFFFFF !important;
}

.dropdown .preloadedTagItemPanel:last-child {
    border-bottom: 0;
}

2
Je pense que c'est une mauvaise solution. Un contrôleur ne doit pas gérer les choses de l'interface utilisateur comme les touches.
Maya Kathrine Andersen

5
Cette réponse contient beaucoup de «bruit», en quelque sorte, contenant beaucoup de balisage qui - pour autant que je puisse voir en un coup d'œil - ne se rapporte pas à la question réelle à portée de main. Il pourrait être plus succinct / utile de condenser le code dans la réponse et de fournir l'exemple complet dans gist / jsfiddle / plnkr.
Cornelius

1
@MartinAndersen, où manipuler une touche dans une application angulaire?
Emanegux

1
Quand je le regarde maintenant, ça semble bien. C'est essentiellement la façon dont les touches ont toujours été gérées avec le modèle d'événement JS.
Maya Kathrine Andersen

0

Je suis un peu en retard .. mais je l' ai trouvé une solution plus simple en utilisant auto-focus.. Cela peut être utile pour les boutons ou autres quand popping un dialog:

<button auto-focus ng-click="func()">ok</button>

Cela devrait être bien si vous voulez appuyer sur le bouton onEspace ou sur Entrer clics.


la question est d'appuyer sur Entrée et de faire quelque chose.
BlaShadow

0

voici ma directive:

mainApp.directive('number', function () {
    return {
        link: function (scope, el, attr) {
            el.bind("keydown keypress", function (event) {
                //ignore all characters that are not numbers, except backspace, delete, left arrow and right arrow
                if ((event.keyCode < 48 || event.keyCode > 57) && event.keyCode != 8 && event.keyCode != 46 && event.keyCode != 37 && event.keyCode != 39) {
                    event.preventDefault();
                }
            });
        }
    };
});

usage:

<input number />

0

vous pouvez utiliser ng-keydown, ng-keyup, ng-press comme celui-ci.

pour déclencher une fonction:

   <input type="text" ng-keypress="function()"/>

ou si vous avez une condition comme quand il appuie sur Échap (27 est le code clé pour échapper)

 <form ng-keydown=" event.which=== 27?cancelSplit():0">
....
</form>

0

Je pense que l'utilisation de document.bind est un peu plus élégante

constructor($scope, $document) {
  var that = this;
  $document.bind("keydown", function(event) {
    $scope.$apply(function(){
      that.handleKeyDown(event);
    });
  });
}

Pour envoyer un document au constructeur du contrôleur:

controller: ['$scope', '$document', MyCtrl]

0
(function(angular) {
  'use strict';
angular.module('dragModule', [])
  .directive('myDraggable', ['$document', function($document) {
    return {
      link: function(scope, element, attr) {
         element.bind("keydown keypress", function (event) {
           console.log('keydown keypress', event.which);
            if(event.which === 13) {
                event.preventDefault();
            }
        });
      }
    };
  }]);
})(window.angular);

0

Tout ce que vous devez faire pour obtenir l'événement est le suivant:

console.log(angular.element(event.which));

Une directive peut le faire, mais ce n'est pas ainsi que vous le faites.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.