Invia modulo premendo Invio con AngularJS


364

In questo caso particolare, quali opzioni devo fare per chiamare questi ingressi una funzione quando premo Invio?

// 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');
    };
}])

Risposte:


518

Angular supporta questo immediatamente. Hai provato ngSubmit sul tuo elemento modulo?

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

MODIFICA: Per il commento relativo al pulsante di invio, vedere Invio di un modulo premendo Invio senza un pulsante di invio che fornisce la soluzione di:

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

Se non ti piace la soluzione nascosta del pulsante di invio, dovrai associare una funzione del controller all'evento Enter keypress o keyup. Questo di solito richiede una direttiva personalizzata, ma la libreria AngularUI ha già una bella soluzione keypress impostata. Vedi http://angular-ui.github.com/

Dopo aver aggiunto la lib angIU, il tuo codice sarebbe simile a:

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

oppure puoi associare la pressione del tasto invio a ogni singolo campo.

Inoltre, vedi queste domande SO per la creazione di una semplice direttiva keypres: Come posso rilevare onKeyUp in AngularJS?

EDIT (2014-08-28): Al momento in cui questa risposta è stata scritta, ng-keypress / ng-keyup / ng-keydown non esisteva come direttive native in AngularJS. Nei commenti qui sotto @ darlan-alves ha una soluzione abbastanza buona con:

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


9
Funziona solo se nel modulo è presente anche un pulsante di invio.
ali

3
Si noti inoltre che questo deve essere un <form> non sembra funzionare su <someElement ng-form = "" ...> che è quello che tendo a usare.
John Culviner,

1
Basta lasciare una nota: se sei finito qui e i pulsanti di invio non funzionano per te, potresti utilizzare un nome errato per la tua funzione di invio. Stavo follemente usando ng-submit="join()"un controller di registrazione che aveva $scope.join = function() {...}e modificando quel nome di funzione per foo()far funzionare nuovamente l'invio del pulsante di invio.
tester

1
Al momento della
stesura di

69
ng-keyup="$event.keyCode == 13 && myFunc()"Davvero fantastico :)
Gonchar Denys,

286

Se vuoi chiamare la funzione senza modulo puoi usare la mia direttiva 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>

Sottopongo altre fantastiche direttive sul mio twitter e sul mio account principale .


2
C'è un modo intelligente per far sì che questo si inneschi ogni volta che premono invio mentre sono sulla tua pagina?
Derek Adair,

1
@EpokK Voglio disabilitare il tasto invio per l'intero modulo, come posso farlo? (Voglio evitare l'invio del modulo con invio)
Antonio Max

47
molto bello, ma secondo la raccomandazione di AngularJs, non dovresti creare direttive, servizi o filtri con prefisso ng-, nel caso in cui una versione ufficiale in seguito usi lo stesso nome.
Neil S

5
Ottima soluzione Ho appena cambiato il nome in keyBind e questa riga "if (event.which === 13) {" in questo "if (event.which === Number (attrs.key)) {" E quindi il mio input in "< input type = "text" bind-key = "doSomething ()" key = "13"> "in modo da poterlo riutilizzare per diversi eventi chiave.
Brian F,

4
IMPORTANTE: l'aggiunta di entrambi gli eventi keydowne keypresssenza una virgola per delimitarli significa che entrambi possono attivarsi contemporaneamente. Ciò potrebbe generare $ rootScope: errori inprog. L'aggiunta di una virgola tra loro crea un disgiuntivo e garantisce solo il ciclo $ digest. Impossibile applicare la modifica poiché è solo un singolo carattere.
Ryan Miller

197

Se hai un solo input puoi usare il tag form.

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

Se hai più di un input o non desideri utilizzare il tag del modulo o desideri collegare la funzionalità del tasto Invio a un campo specifico, puoi incorporarlo a un input specifico come segue:

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

2
Questo è un modo intelligente di farlo senza nemmeno dover scrivere la tua direttiva
Charlie Martin,

59
Ancora più breve: <input ng-keyup = "$ event.keyCode == 13 && myFunc ()" ... />
Darlan Alves,

Funziona benissimo, ho usato la direttiva ng-keyup, ma ho un grosso problema con esso, se ho solo un campo di testo, invia il modulo completo (postback) ma non lo voglio. Ho già provato ng-keyup = "$ event.keyCode == 13 && onTextBoxKeyUp ($ event)" e nella funzione "event.preventDefault ();", ma non ha aiutato; (
SharpNoiZy

questo è più breve ma tenendo a mente l'approccio DRY, creerei comunque direttiva e la utilizzerei con direttiva.
Atul Chaudhary,

Questo può essere problematico a seconda del contesto: ho una forma in cui ho due pulsanti (interfaccia guidata come procedura guidata), con il pulsante 'indietro' e 'successivo', il comportamento predefinito facendo clic sul tasto 'invio' è il pulsante Indietro. Ora, quando si utilizza il codice sopra, il pulsante Indietro ottiene CLICCATO PRIMA, quindi viene chiamato il codice myFunction () (che a sua volta arriva alla parte successiva della procedura guidata) Quindi, la mia procedura guidata va INDIETRO per un po ', quindi va avanti. La soluzione di @ EpokK funziona perfettamente per me.
Vishwajeet Vatharkar,

33

Volevo qualcosa di un po 'più estensibile / semantico rispetto alle risposte fornite, quindi ho scritto una direttiva che prende un oggetto javascript in un modo simile al built-in ngClass:

HTML

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

I valori dell'oggetto vengono valutati nel contesto dell'ambito della direttiva - assicurarsi che siano racchiusi tra virgolette singole, altrimenti tutte le funzioni verranno eseguite quando la direttiva viene caricata (!)

Quindi per esempio: esc : 'clear()' invece diesc : 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]);
                    });
                }
            });
        };
    }]);

Ottengo un errore di analisi HTML angluarjs quando provo ad aggiungere una variabile stringa nella funzione. key-bind = "{invio: 'vm.doTheThing (' myVar ')'}"
MaylorTaylor

Ho anche notato che se uso la funzione con un oggetto come variabile, la funzione si verifica più di una volta. Il codice seguente rimuove 2+ elementi quando eseguo questo. key-bind = "{enter: 'vm.removeItem (item)'}"
MaylorTaylor

1
@MaylorTaylor per il primo numero, usa diversi tipi di virgolette, cioè'vm.doTheThing("myVar")'
AlexFoxGill


14

Direttiva molto buona, pulita e semplice con maiusc + invio supporto:

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);
                       }
                 }
            });
        }
    }
});

5

Se vuoi anche la convalida dei dati

<!-- 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'importante aggiunta qui è $loginForm.$validche convaliderà il modulo prima di eseguire la funzione. Dovrai aggiungere altri attributi per la convalida che vanno oltre lo scopo di questa domanda.

In bocca al lupo.


2

Volevo solo sottolineare che nel caso di avere un pulsante di invio nascosto, puoi semplicemente usare la direttiva ngShow e impostarlo su false in questo modo:

HTML

<form ng-submit="myFunc()">
    <input type="text" name="username">
    <input type="submit" value="submit" ng-show="false">
</form>

1
+1 <button ng-show="false"></button>è ancora più breve. Non è necessario impostare il valore di un pulsante invisibile.
musa,

type="submit"Avevo capito che per innescare la direttiva ng-submit, un input di ... Suppongo che il valore potesse essere ignorato, ma credo che il primo sia necessario.
Landesko,

1

Usa ng-submit e avvolgi entrambi gli input in tag di moduli separati:

<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>

Il wrapping di ciascun campo di input nel proprio tag del modulo consente a INVIO di invocare l'invio su entrambi i moduli. Se usi un tag modulo per entrambi, dovrai includere un pulsante di invio.


0

Sarà leggermente più ordinato usando una classe CSS invece di ripetere gli stili in linea.

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>

0

FWIW - Ecco una direttiva che ho usato per un bootstrap modale di conferma / avviso, senza la necessità di un <form>

(basta cambiare l'azione jQuery click per quello che ti piace e aggiungere data-easy-dismissal tuo tag 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);
            });
        }
    };
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.