Prześlij formularz po naciśnięciu Enter za pomocą AngularJS

364

W tym konkretnym przypadku, jakie opcje muszę wprowadzić, aby te wejścia wywoływały funkcję po naciśnięciu klawisza Enter?

// 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
źródło

Odpowiedzi:

518

Angular obsługuje to po wyjęciu z pudełka. Próbowałeś już ngSubmit na swoim formularzu?

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

EDYCJA: Zgodnie z komentarzem dotyczącym przycisku wysyłania , patrz Przesyłanie formularza przez naciśnięcie Enter bez przycisku wysyłania, co daje rozwiązanie:

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

Jeśli nie podoba Ci się rozwiązanie ukrytego przycisku przesyłania, musisz powiązać funkcję kontrolera ze zdarzeniem Enter lub naciśnięciem klawisza. Zwykle wymaga to niestandardowej dyrektywy, ale biblioteka AngularUI ma już skonfigurowane ładne naciśnięcie klawisza. Zobacz http://angular-ui.github.com/

Po dodaniu biblioteki angularUI lib kod będzie wyglądał następująco:

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

lub możesz przypisać klawisz Enter do każdego pola.

Zobacz także następujące pytania SO dotyczące tworzenia prostej dyrektywy keypres: Jak wykryć onKeyUp w AngularJS?

EDYCJA (2014-08-28): W momencie pisania tej odpowiedzi ng-keypress / ng-keyup / ng-keydown nie istniały jako natywne dyrektywy w AngularJS. W komentarzach poniżej @ darlan-alves ma całkiem dobre rozwiązanie z:

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

eterps
źródło
9
Działa to tylko wtedy, gdy w formularzu mam również przycisk wysyłania.
Ali
3
Zauważ też, że MUSI to być <form>, wydaje się, że nie działa na <someElement ng-form = "" ... ...> co zwykle używam.
John Culviner
1
Po prostu zostawiając notatkę: jeśli skończyłeś tutaj i przyciski przesyłania nie działają dla Ciebie, być może używasz złej nazwy dla funkcji wysyłania. Głupio używałem ng-submit="join()"dla kontrolera rejestracji, który miał $scope.join = function() {...}i zmienił nazwę tej funkcji, aby ponownie foo()włączyć przesyłanie przycisku Enter.
tester
1
W czasie, gdy ta odpowiedź była napisana, naciśnięcie klawisza ng /
ke
69
ng-keyup="$event.keyCode == 13 && myFunc()"Naprawdę niesamowite :)
Gonchar Denys
286

Jeśli chcesz wywołać funkcję bez formularza, możesz użyć mojej dyrektywy 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>

Przekazuję inne niesamowite dyrektywy na moim Twitterze i koncie GIST .

EpokK
źródło
2
Czy istnieje sprytny sposób, aby uruchomić go za każdym razem, gdy naciśniesz Enter na swojej stronie?
Derek Adair
1
@EpokK Chcę wyłączyć klawisz Enter dla całego formularza, jak mogę to zrobić? (Chcę uniknąć przesyłania formularza za pomocą enter)
Antonio Max
47
bardzo fajnie, ale zgodnie z zaleceniem AngularJs, nie powinieneś tworzyć dyrektyw, usług ani filtrów, które mają przedrostek ng-, na wypadek, gdyby oficjalne wydanie później używało tej samej nazwy.
Neil S
5
Świetne rozwiązanie. Właśnie zmieniłem nazwę na keyBind i ten wiersz „if (event.which === 13) {„ na to ”if (event.which === Number (attrs.key)) {” A potem moje wejście do „< input type = "text" bind-key = "doSomething ()" key = "13"> ", abym mógł użyć go ponownie dla różnych kluczowych zdarzeń.
Brian F.
4
WAŻNE: Dodanie zarówno keydowni keypresswydarzenia bez przecinka, aby oddzielić je oznacza zarówno może wystrzelić jednocześnie. Może to spowodować odrodzenie $ rootScope: błędy inprog. Dodanie przecinka między nimi powoduje rozłączenie i zapewnia, że ​​występuje tylko cykl $ digest. Nie można zastosować zmiany, ponieważ jest to tylko jeden znak.
Ryan Miller
197

Jeśli masz tylko jedno wejście, możesz użyć znacznika formularza.

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

Jeśli masz więcej niż jedno wejście lub nie chcesz używać znacznika formularza, lub chcesz dołączyć funkcję enter-key do określonego pola, możesz wstawić je do określonego wejścia w następujący sposób:

<input ng-keyup="$event.keyCode == 13 && myFunc()" ...>
MM
źródło
2
Jest to sprytny sposób na zrobienie tego bez konieczności pisania własnej dyrektywy
Charlie Martin
59
Jeszcze krótszy: <input ng-keyup = "$ event.keyCode == 13 && myFunc ()" ... />
Darlan Alves
Działa świetnie, użyłem dyrektywy ng-keyup, ale mam z nią jeden duży problem, jeśli mam tylko jedno pole tekstowe, on przesyła pełny formularz (postback), ale nie chcę tego. Próbowałem już ng-keyup = "$ event.keyCode == 13 && onTextBoxKeyUp ($ event)" oraz w funkcji "event.preventDefault ();", ale nie
pomogłem
jest to krótsze, ale pamiętając o podejściu SUCHYM, nadal tworzyłbym dyrektywę i używałbym jej razem z dyrektywą.
Atul Chaudhary,
Może to być problematyczne w zależności od kontekstu - mam formę, w której mam dwa przyciski (interfejs podobny do kreatora), z przyciskami „wstecz” i „następny”, domyślne zachowanie po kliknięciu przycisku „enter” to przycisk powrotu. Teraz, gdy używasz powyższego kodu, przycisk Wstecz dostaje KLIKNIĘCIE PIERWSZY, a następnie wywoływany jest kod myFunction () (który z kolei przechodzi do następnej części kreatora). Mój kreator wraca na chwilę, a następnie idzie do przodu. @ Rozwiązanie EpokK działa dla mnie idealnie.
Vishwajeet Vatharkar
33

Chciałem czegoś bardziej rozszerzalnego / semantycznego niż podane odpowiedzi, więc napisałem dyrektywę, która pobiera obiekt javascript w podobny sposób do wbudowanego ngClass:

HTML

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

Wartości obiektu są oceniane w kontekście zakresu dyrektywy - upewnij się, że są ujęte w pojedyncze cudzysłowy, w przeciwnym razie wszystkie funkcje zostaną wykonane po załadowaniu dyrektywy (!)

Na przykład: esc : 'clear()'zamiastesc : 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
źródło
Podczas próby dodania zmiennej ciągowej w funkcji pojawia się błąd analizy składni HTMLu angluarjs. key-bind = "{enter: 'vm.doTheThing (' myVar ')'}"
MaylorTaylor
Zauważyłem również, że jeśli używam funkcji z Object jako zmienną, funkcja ta występuje więcej niż raz. Poniższy kod usuwa ponad 2 elementy po uruchomieniu tego. key-bind = "{enter: 'vm.removeItem (item)'}"
MaylorTaylor
1
@MaylorTaylor w pierwszym wydaniu, użyj różnych rodzajów cytatów, tj.'vm.doTheThing("myVar")'
AlexFoxGill
14

Bardzo dobra, czysta i prosta dyrektywa z obsługą 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);
                       }
                 }
            });
        }
    }
});
Wlatko
źródło
5

Jeśli chcesz także sprawdzania poprawności danych

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

Ważnym dodatkiem jest tutaj, $loginForm.$validktóry zweryfikuje formularz przed wykonaniem funkcji. Będziesz musiał dodać inne atrybuty do weryfikacji, które wykraczają poza zakres tego pytania.

Powodzenia.

Akash
źródło
2

Chciałem tylko zaznaczyć, że w przypadku posiadania ukrytego przycisku wysyłania możesz po prostu użyć dyrektywy ngShow i ustawić ją na false:

HTML

<form ng-submit="myFunc()">
    <input type="text" name="username">
    <input type="submit" value="submit" ng-show="false">
</form>
landesko
źródło
1
+1 <button ng-show="false"></button>jest jeszcze krótszy. Nie ma potrzeby ustawiania wartości niewidocznego przycisku.
musa
Zrozumiałem, że aby uruchomić dyrektywę ng-poddanie, wkład type="submit"... Przypuszczam, że wartość można zignorować, ale uważam, że ta pierwsza jest konieczna.
landesko
1

Użyj ng-upload i po prostu zawiń oba dane wejściowe w osobnych tagach formularza:

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

Zawinięcie każdego pola wejściowego we własnym znaczniku formularza pozwala ENTER na wywołanie przedłożenia w dowolnym formularzu. Jeśli użyjesz jednego tagu formularza dla obu, musisz dołączyć przycisk przesyłania.

Myclamm
źródło
0

Będzie nieco łatwiejsza przy użyciu klasy CSS zamiast powtarzania stylów wbudowanych.

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
źródło
0

FWIW - Oto dyrektywa, której użyłem dla podstawowego modalu bootstrap potwierdzenia / alertu, bez potrzeby <form>

(po prostu wyłącz akcję kliknięcia jQuery dla tego, co chcesz i dodaj data-easy-dismissdo tagu modalnego)

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
źródło