Soumettez le formulaire en appuyant sur Entrée avec AngularJS

364

Dans ce cas particulier, quelles options dois-je faire pour que ces entrées appellent une fonction lorsque j'appuie sur Entrée?

// HTML view //
<form>
    <input type="text" ng-model="name" <!-- Press ENTER and call myFunc --> />
    <br />
    <input type="text" ng-model="email" <!-- Press ENTER and call myFunc --> />
</form>

// Controller //
.controller('mycontroller', ['$scope',function($scope) {
    $scope.name = '';
    $scope.email = '';
    // Function to be called when pressing ENTER
    $scope.myFunc = function() {
       alert('Submitted');
    };
}])
Ali
la source

Réponses:

518

Angular prend cela en charge. Avez-vous essayé ngSubmit sur votre élément de formulaire?

<form ng-submit="myFunc()" ng-controller="mycontroller">
   <input type="text" ng-model="name" />
    <br />
    <input type="text" ng-model="email" />
</form>

MODIFIER: Selon le commentaire concernant le bouton Soumettre , voir Soumettre un formulaire en appuyant sur Entrée sans bouton Soumettre ce qui donne la solution de:

<input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;"/>

Si vous n'aimez pas la solution de bouton d'envoi caché, vous devrez lier une fonction de contrôleur à l'événement Enter keypress ou keyup. Cela nécessite normalement une directive personnalisée, mais la bibliothèque AngularUI a déjà une belle solution de pression de touches configurée. Voir http://angular-ui.github.com/

Après avoir ajouté la lib angularUI, votre code serait quelque chose comme:

<form ui-keypress="{13:'myFunc($event)'}">
  ... input fields ...
</form>

ou vous pouvez lier la touche Entrée à chaque champ individuel.

Consultez également ces questions SO pour créer une simple directive keypres: Comment puis-je détecter onKeyUp dans AngularJS?

EDIT (2014-08-28): Au moment où cette réponse a été écrite, ng-keypress / ng-keyup / ng-keydown n'existait pas en tant que directives natives dans AngularJS. Dans les commentaires ci-dessous @ darlan-alves a une assez bonne solution avec:

<input ng-keyup="$event.keyCode == 13 && myFunc()"... />

eterps
la source
9
Cela ne fonctionne que si j'ai également un bouton d'envoi dans le formulaire.
ali
3
Notez également que cela DOIT être un <form> il ne semble pas fonctionner sur <someElement ng-form = "" ...> qui est ce que j'ai tendance à utiliser.
John Culviner du
1
Juste laisser une note: si vous vous êtes retrouvé ici et que les boutons d'envoi ne fonctionnent pas pour vous, vous pourriez utiliser un mauvais nom pour votre fonction d'envoi. J'utilisais stupidement ng-submit="join()"un contrôleur d'enregistrement qui avait $scope.join = function() {...}et je changeais le nom de la fonction pour que la foo()soumission du bouton d'entrée fonctionne à nouveau.
testeur
1
Au moment où cette réponse a été écrite, ng-keypress / ng-keyup n'existait pas dans Angular
eterps
69
ng-keyup="$event.keyCode == 13 && myFunc()"Vraiment génial :)
Gonchar Denys
286

Si vous voulez appeler une fonction sans formulaire, vous pouvez utiliser ma directive ngEnter:

Javascript :

angular.module('yourModuleName').directive('ngEnter', function() {
        return function(scope, element, attrs) {
            element.bind("keydown keypress", function(event) {
                if(event.which === 13) {
                    scope.$apply(function(){
                        scope.$eval(attrs.ngEnter, {'event': event});
                    });

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

HTML :

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

Je soumets d'autres directives impressionnantes sur mon twitter et mon compte essentiel .

EpokK
la source
2
Existe-t-il un moyen intelligent pour que cela se déclenche à chaque fois qu'ils entrent sur votre page?
Derek Adair
1
@EpokK Je veux désactiver la touche Entrée pour tout le formulaire, comment faire? (Je veux éviter la soumission du formulaire avec enter)
Antonio Max
47
très bien, mais selon la recommandation d'AngularJs, vous ne devez pas créer de directives, de services ou de filtres préfixés avec ng-, au cas où une version officielle utiliserait plus tard le même nom.
Neil S
5
Excellente solution. Je viens de changer le nom en keyBind et cette ligne "if (event.which === 13) {" en ceci "if (event.which === Number (attrs.key)) {" Et puis mon entrée dans "< input type = "text" bind-key = "doSomething ()" key = "13"> "afin que je puisse le réutiliser pour différents événements clés.
Brian F
4
IMPORTANT: l'ajout des événements keydownet keypresssans virgule pour les délimiter signifie que les deux peuvent se déclencher simultanément. Cela est susceptible de générer des erreurs $ rootScope: inprog. L'ajout d'une virgule entre eux crée un caractère disjonctif et garantit que seul le cycle $ digest se produit. Impossible d'appliquer la modification car il ne s'agit que d'un seul caractère.
Ryan Miller
197

Si vous n'avez qu'une seule entrée, vous pouvez utiliser la balise de formulaire.

<form ng-submit="myFunc()" ...>

Si vous avez plusieurs entrées, ou si vous ne souhaitez pas utiliser la balise de formulaire, ou si vous souhaitez attacher la fonctionnalité de touche d'entrée à un champ spécifique, vous pouvez l'inclure dans une entrée spécifique comme suit:

<input ng-keyup="$event.keyCode == 13 && myFunc()" ...>
MM
la source
2
C'est une façon intelligente de le faire sans même avoir à écrire votre propre directive
Charlie Martin
59
Encore plus court: <input ng-keyup = "$ event.keyCode == 13 && myFunc ()" ... />
Darlan Alves
Fonctionne très bien, j'ai utilisé la directive ng-keyup, mais j'ai un gros problème avec elle, si je n'ai qu'un seul champ de texte, il soumet le formulaire complet (postback) mais je ne le veux pas. J'ai déjà essayé ng-keyup = "$ event.keyCode == 13 && onTextBoxKeyUp ($ event)" et dans la fonction "event.preventDefault ();", mais
je
c'est plus court mais en gardant l'approche DRY dans mon esprit, je créerais toujours une directive et l'utiliserais avec directive.
Atul Chaudhary
Cela peut être problématique selon le contexte - j'ai un formulaire dans lequel j'ai deux boutons, (interface de type assistant), avec les boutons `` retour '' et `` suivant '', le comportement par défaut en cliquant sur la touche `` entrer '' est le bouton de retour. Maintenant, lorsque vous utilisez le code ci-dessus, le bouton de retour est CLIQUEZ EN PREMIER, puis le code myFunction () est appelé (qui à son tour, passe à la partie suivante de l'assistant) .Ainsi, mon assistant revient en arrière pendant un certain temps, puis il avance. La solution d'EpokK fonctionne parfaitement pour moi.
Vishwajeet Vatharkar
33

Je voulais quelque chose d'un peu plus extensible / sémantique que les réponses données, j'ai donc écrit une directive qui prend un objet javascript de la même manière que le intégré ngClass :

HTML

<input key-bind="{ enter: 'go()', esc: 'clear()' }" type="text"></input>

Les valeurs de l'objet sont évaluées dans le contexte de la portée de la directive - assurez-vous qu'elles sont mises entre guillemets simples, sinon toutes les fonctions seront exécutées lorsque la directive sera chargée (!)

Ainsi, par exemple: esc : 'clear()'au lieu deesc : clear()

Javascript

myModule
    .constant('keyCodes', {
        esc: 27,
        space: 32,
        enter: 13,
        tab: 9,
        backspace: 8,
        shift: 16,
        ctrl: 17,
        alt: 18,
        capslock: 20,
        numlock: 144
    })
    .directive('keyBind', ['keyCodes', function (keyCodes) {
        function map(obj) {
            var mapped = {};
            for (var key in obj) {
                var action = obj[key];
                if (keyCodes.hasOwnProperty(key)) {
                    mapped[keyCodes[key]] = action;
                }
            }
            return mapped;
        }

        return function (scope, element, attrs) {
            var bindings = map(scope.$eval(attrs.keyBind));
            element.bind("keydown keypress", function (event) {
                if (bindings.hasOwnProperty(event.which)) {
                    scope.$apply(function() {
                         scope.$eval(bindings[event.which]);
                    });
                }
            });
        };
    }]);
AlexFoxGill
la source
J'obtiens une erreur d'analyse HTML angluarjs lorsque j'essaie d'ajouter une variable de chaîne dans la fonction. key-bind = "{enter: 'vm.doTheThing (' myVar ')'}"
MaylorTaylor
A également remarqué que si j'utilise une fonction avec un objet comme variable, la fonction se produit plus d'une fois. Le code ci-dessous supprime plus de 2 éléments lorsque j'exécute cela. key-bind = "{enter: 'vm.removeItem (item)'}"
MaylorTaylor
1
@MaylorTaylor pour le premier numéro, utilisez différents types de citations, c'est'vm.doTheThing("myVar")'
AlexFoxGill
14

Directive très bonne, propre et simple avec support shift + enter:

app.directive('enterSubmit', function () {
    return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
            elem.bind('keydown', function(event) {
                 var code = event.keyCode || event.which;
                 if (code === 13) {
                       if (!event.shiftKey) {
                            event.preventDefault();
                            scope.$apply(attrs.enterSubmit);
                       }
                 }
            });
        }
    }
});
Vlatko
la source
5

Si vous souhaitez également la validation des données

<!-- form -->
<form name="loginForm">
...
  <input type="email" ng-keyup="$loginForm.$valid && $event.keyCode == 13 && signIn()" ng-model="email"... />
  <input type="password" ng-keyup="$loginForm.$valid && $event.keyCode == 13 && signIn()" ng-model="password"... />
</form>

L'ajout important ici est de $loginForm.$validvalider le formulaire avant d'exécuter la fonction. Vous devrez ajouter d'autres attributs pour la validation qui sortent du cadre de cette question.

Bonne chance.

Akash
la source
2

Je voulais juste souligner que dans le cas d'un bouton d'envoi caché, vous pouvez simplement utiliser la directive ngShow et la définir sur false comme suit:

HTML

<form ng-submit="myFunc()">
    <input type="text" name="username">
    <input type="submit" value="submit" ng-show="false">
</form>
landesko
la source
1
+1 <button ng-show="false"></button>est encore plus court. Pas besoin de définir la valeur d'un bouton invisible.
musa
type="submit"J'ai cru comprendre que pour déclencher la directive ng-submit, une entrée de ... Je suppose que la valeur pouvait être ignorée, mais je pense que la première est nécessaire.
landesko
1

Utilisez ng-submit et enveloppez simplement les deux entrées dans des balises de formulaire distinctes:

<div ng-controller="mycontroller">

  <form ng-submit="myFunc()">
    <input type="text" ng-model="name" <!-- Press ENTER and call myFunc --> />
  </form>

  <br />

  <form ng-submit="myFunc()">
    <input type="text" ng-model="email" <!-- Press ENTER and call myFunc --> />
  </form>

</div>

Envelopper chaque champ de saisie dans sa propre balise de formulaire permet à ENTRÉE d'appeler soumettre sur l'un ou l'autre formulaire. Si vous utilisez une balise de formulaire pour les deux, vous devrez inclure un bouton d'envoi.

Myclamm
la source
0

Sera légèrement plus net en utilisant une classe CSS au lieu de répéter des styles en ligne.

CSS

input[type=submit] {
    position: absolute;
    left: -9999px;
}

HTML

<form ng-submit="myFunc()">
    <input type="text" ng-model="name" />
    <br />
    <input type="text" ng-model="email" />
    <input type="submit" />
</form>
guya
la source
0

FWIW - Voici une directive que j'ai utilisée pour un mode d'amorçage de confirmation / alerte de base, sans avoir besoin d'un <form>

(il suffit de désactiver l'action de clic jQuery pour tout ce que vous aimez et de l'ajouter data-easy-dismissà votre balise modale)

app.directive('easyDismiss', function() {
    return {
        restrict: 'A',
        link: function ($scope, $element) {

            var clickSubmit = function (e) {
                if (e.which == 13) {
                    $element.find('[type="submit"]').click();
                }
            };

            $element.on('show.bs.modal', function() {
                $(document).on('keypress', clickSubmit);
            });

            $element.on('hide.bs.modal', function() {
                $(document).off('keypress', clickSubmit);
            });
        }
    };
});
Andrew Appleby
la source