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

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()"... />


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 .


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()" ...>

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

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

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.


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>

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.


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>

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);
            });
        }
    };
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.