Kirim formulir dengan menekan Enter dengan AngularJS

364

Dalam kasus khusus ini, opsi apa yang saya miliki untuk membuat input ini memanggil fungsi ketika saya menekan 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
sumber

Jawaban:

518

Sudut mendukung ini di luar kotak. Sudahkah Anda mencoba ngSubmit pada elemen formulir Anda?

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

EDIT: Per komentar tentang tombol kirim, lihat Mengirimkan formulir dengan menekan enter tanpa tombol kirim yang memberikan solusi:

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

Jika Anda tidak menyukai solusi tombol kirim tersembunyi, Anda harus mengikat fungsi pengontrol ke acara Enter penekanan tombol atau keyup. Ini biasanya memerlukan arahan khusus, tetapi pustaka AngularUI sudah menyiapkan solusi penekanan tombol yang bagus. Lihat http://angular-ui.github.com/

Setelah menambahkan lib angularUI, kode Anda akan menjadi seperti:

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

atau Anda dapat mengikat tombol masuk ke setiap bidang individual.

Juga, lihat pertanyaan SO ini untuk membuat arahan keypres sederhana: Bagaimana cara mendeteksi onKeyUp di AngularJS?

EDIT (2014-08-28): Pada saat jawaban ini ditulis, ng-keypress / ng-keyup / ng-keydown tidak ada sebagai arahan asli di AngularJS. Dalam komentar di bawah ini @ darlan-alves memiliki solusi yang cukup bagus dengan:

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

eterps
sumber
9
Ini hanya berfungsi jika saya memiliki tombol kirim di dalam formulir juga.
ali
3
Perhatikan juga bahwa ini HAS untuk menjadi <form> sepertinya tidak berfungsi pada <someElement ng-form = "" ...> yang cenderung saya gunakan.
John Culviner
1
Hanya meninggalkan catatan: Jika Anda berakhir di sini dan mengirimkan tombol tidak berfungsi untuk Anda, Anda bisa menggunakan nama buruk untuk fungsi kirim Anda. Saya bodoh menggunakan ng-submit="join()"pengontrol registrasi yang memiliki $scope.join = function() {...}dan mengubah nama fungsi untuk foo()mendapatkan pengiriman tombol enter bekerja lagi.
tester
1
Pada saat jawaban ini ditulis, ng-keypress / ng-keyup tidak ada di Angular
eterps
69
ng-keyup="$event.keyCode == 13 && myFunc()"Sungguh luar biasa :)
Gonchar Denys
286

Jika Anda ingin memanggil fungsi tanpa formulir, Anda dapat menggunakan arahan ngEnter saya:

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>

Saya mengirimkan arahan luar biasa kepada orang lain di twitter dan akun utama saya .

EpokK
sumber
2
Apakah ada cara pintar untuk memicu ini kapan saja mereka menekan enter saat berada di halaman Anda?
Derek Adair
1
@ EpokK Saya ingin menonaktifkan kunci enter untuk seluruh formulir, bagaimana saya bisa melakukannya? (Saya ingin menghindari pengiriman formulir dengan memasukkan)
Antonio Max
47
sangat bagus, tetapi sesuai rekomendasi AngularJs, Anda tidak boleh membuat arahan, layanan, atau filter yang diawali dengan ng, jika seandainya rilis resmi nanti menggunakan nama yang sama.
Neil S
5
Solusi bagus Saya baru saja mengubah nama menjadi keyBind dan baris ini "if (event.which === 13) {" to this "if (event.which === Number (attrs.key)) {" Lalu masukan saya ke "< tipe input = "text" bind-key = "doSomething ()" key = "13"> "sehingga saya bisa menggunakannya kembali untuk berbagai peristiwa penting.
Brian F
4
PENTING: Menambahkan keduanya keydowndan keypressacara tanpa koma untuk membatasi keduanya berarti keduanya dapat menyala secara bersamaan. Ini kemungkinan akan menghasilkan $ rootScope: kesalahan inprog. Menambahkan koma di antara mereka menciptakan disjungtif, dan memastikan hanya siklus $ digest yang terjadi. Tidak dapat menerapkan hasil edit karena hanya satu karakter.
Ryan Miller
197

Jika Anda hanya memiliki satu input, Anda dapat menggunakan tag formulir.

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

Jika Anda memiliki lebih dari satu input, atau tidak ingin menggunakan tag formulir, atau ingin melampirkan fungsionalitas tombol-enter ke bidang tertentu, Anda bisa memasukkannya ke input tertentu sebagai berikut:

<input ng-keyup="$event.keyCode == 13 && myFunc()" ...>
MM
sumber
2
Ini adalah cara cerdas untuk melakukan ini tanpa harus menulis arahan Anda sendiri
Charlie Martin
59
Bahkan lebih pendek: <input ng-keyup = "$ event.keyCode == 13 && myFunc ()" ... />
Darlan Alves
Berfungsi bagus, saya menggunakan arahan ng-keyup, tapi saya punya satu masalah besar dengan itu, jika saya hanya memiliki satu bidang teks, ia mengirimkan formulir lengkap (postback) tetapi saya tidak menginginkannya. Saya sudah mencoba ng-keyup = "$ event.keyCode == 13 && onTextBoxKeyUp ($ event)" dan dalam fungsi "event.preventDefault ();", tetapi tidak membantu; (
SharpNoiZy
ini lebih pendek tetapi menjaga pendekatan KERING dalam pikiran saya saya masih akan membuat arahan dan menggunakannya dengan arahan.
Atul Chaudhary
Ini mungkin bermasalah tergantung pada konteksnya - Saya memiliki bentuk di mana saya memiliki dua tombol, (antarmuka seperti penyihir), dengan tombol 'kembali' dan 'berikutnya', perilaku default mengklik tombol 'enter' adalah tombol kembali. Sekarang, ketika menggunakan kode di atas, tombol kembali mendapatkan CLICKED FIRST, dan kemudian kode myFunction () dipanggil (yang pada gilirannya, dapatkan ke bagian berikutnya dari wizard) Jadi, wizard saya akan KEMBALI untuk sementara waktu, dan kemudian maju. Solusi @ EpokK sangat cocok untuk saya.
Vishwajeet Vatharkar
33

Saya menginginkan sesuatu yang sedikit lebih extensible / semantik daripada jawaban yang diberikan jadi saya menulis arahan yang mengambil objek javascript dengan cara yang mirip dengan built-in ngClass:

HTML

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

Nilai-nilai objek dievaluasi dalam konteks ruang lingkup direktif - pastikan mereka terbungkus dalam tanda kutip tunggal jika tidak semua fungsi akan dieksekusi ketika direktif dimuat (!)

Jadi misalnya: esc : 'clear()'bukannyaesc : 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
sumber
Saya mendapatkan kesalahan parse HTML angluarjs ketika saya mencoba untuk menambahkan variabel string dalam fungsi. key-bind = "{enter: 'vm.doTheThing (' myVar ')'}"
MaylorTaylor
Juga perhatikan bahwa jika saya menggunakan fungsi dengan Objek sebagai variabel, fungsi terjadi lebih dari satu kali. Kode di bawah ini menghapus 2+ item ketika saya menjalankan ini. key-bind = "{enter: 'vm.removeItem (item)'}"
MaylorTaylor
1
@MaylorTaylor untuk masalah pertama, gunakan berbagai jenis kutipan yaitu'vm.doTheThing("myVar")'
AlexFoxGill
14

Sangat bagus, bersih dan arahan sederhana dengan dukungan 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
sumber
5

Jika Anda ingin validasi data juga

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

Tambahan penting di sini adalah $loginForm.$valid yang akan memvalidasi formulir sebelum menjalankan fungsi. Anda harus menambahkan atribut lain untuk validasi yang berada di luar cakupan pertanyaan ini.

Semoga berhasil.

Akash
sumber
2

Hanya ingin menunjukkan bahwa dalam kasus memiliki tombol kirim tersembunyi, Anda bisa menggunakan arahan ngShow dan mengaturnya ke false seperti:

HTML

<form ng-submit="myFunc()">
    <input type="text" name="username">
    <input type="submit" value="submit" ng-show="false">
</form>
Landesko
sumber
1
+1 <button ng-show="false"></button>bahkan lebih pendek. Tidak perlu mengatur nilai tombol yang tidak terlihat.
musa
Itu pemahaman saya bahwa untuk memicu arahan ng-submit, masukan dari type="submit"... Saya kira nilai bisa diabaikan tetapi saya percaya yang pertama diperlukan.
landesko
1

Gunakan ng-kirim dan bungkus kedua input dalam tag formulir terpisah:

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

Membungkus setiap bidang input dalam bentuknya sendiri memungkinkan ENTER untuk meminta pengiriman pada salah satu formulir. Jika Anda menggunakan satu tag formulir untuk keduanya, Anda harus memasukkan tombol kirim.

Myclamm
sumber
0

Akan sedikit lebih rapi menggunakan kelas CSS bukannya mengulang gaya inline.

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

FWIW - Ini adalah arahan yang saya gunakan untuk modal dasar konfirmasi / peringatan bootstrap, tanpa perlu a <form>

(cukup alihkan tindakan klik jQuery untuk apa pun yang Anda suka, dan tambahkan data-easy-dismisske tag modal Anda)

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
sumber