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.