Submit form on pressing Enter with AngularJS
Asked Answered
J

13

369

In this particular case, what options do I have to make these inputs call a function when I press Enter?

Html:

<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');
    };
}])
Jonna answered 14/3, 2013 at 18:16 Comment(0)
L
522

Angular supports this out of the box. Have you tried ngSubmit on your form element?

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

EDIT: Per the comment regarding the submit button, see Submitting a form by pressing enter without a submit button which gives the solution of:

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

If you don't like the hidden submit button solution, you'll need to bind a controller function to the Enter keypress or keyup event. This normally requires a custom directive, but the AngularUI library has a nice keypress solution set up already. See http://angular-ui.github.com/

After adding the angularUI lib, your code would be something like:

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

or you can bind the enter keypress to each individual field.

Also, see this SO questions for creating a simple keypres directive: How can I detect onKeyUp in AngularJS?

EDIT (2014-08-28): At the time this answer was written, ng-keypress/ng-keyup/ng-keydown did not exist as native directives in AngularJS. In the comments below @darlan-alves has a pretty good solution with:

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

Layer answered 14/3, 2013 at 19:5 Comment(14)
It only works if I have a submit button inside the form, too.Jonna
I'll go with the custom directive, I can't use angular-ui. ThanksJonna
What about ng-change?Signore
The downside to this is ng-submit automatically checks form validity. ui-keypress won't AFAICT.Almena
Also note that this HAS to be a <form> it doesn't seem to work on <someElement ng-form="" ...> which is what I tend to use.Jorin
So basically ng-submit only works when there's a submit button inside the form? Why not clone the ng-submit code, but just remove the part where it requires a submit button, and keep all the validation code.Signore
Just leaving a note: If you've ended up here and submit buttons don't work for you, you could be using a bad name for your submit function. I was foolishly using ng-submit="join()" for a registration controller that had $scope.join = function() {...} and changing that function name to foo() got enter-button submission working again.Backstitch
What's different between ui-keypress and the built-in ng-keypress?Chafin
At the time this answer was written, ng-keypress/ng-keyup did not exist in AngularLayer
ng-keyup="$event.keyCode == 13 && myFunc()" Really awesome :)Putnem
Just in case if someone is ignorant. Keep in mind that input type="button" will not trigger form submit. It needs to be input type="submit" buttonTheiss
... late to the party, but a hidden input with name submit <input type="hidden" name="submit" /> will do the same trick as an actual submit button in terms of making the enter keypress submit a form, which I find elegant enough, compared to hiding the real one away from the screen. I would replace that in this post, but I don't want to put words in @Layer posts. I also find a hidden input more elegant than the keyup hack.Coachman
ng-keyup="$event.keyCode == 13 && myFunc()" this dose not work in FirefoxPhotoelectron
At least as of Firefox 54.0.1 (64-bit) on Mac OS X the ng-keyup answer works.Edric
Z
289

If you want to call function without form you can use my ngEnter directive:

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>

I submit others awesome directives on my twitter and my gist account.

Zeiler answered 28/6, 2013 at 12:25 Comment(14)
Is there a clever way to get this to trigger any time they hit enter while on your page?Rutharuthann
@Zeiler I wanna disable the enter key for the entire form, how can I do that? (I want to avoid form submission with enter)Extracellular
@AntonioMax You could just have an extra flag within the directive that checks whether you want to person to be able to submit or notAndesine
very nice, but as per AngularJs' reccomendation, you shouldn't create directives, services, or filters that are prefixed with ng-, in case an official release later uses the same name.Achromatize
Great solution. I just changed the name to keyBind and this line "if(event.which === 13) {" to this "if(event.which === Number(attrs.key)) {" And then my input to "<input type="text" bind-key="doSomething()" key="13">" so that I could re-use it for different key events.Tocsin
@Derek Adair: I'm quite new to angular directives, but I should try to use, instead of element.bind(..., window.bind(......Muscovado
A very similar answer is posted on this question: How to use a keypress event in angularjsDoralynne
IMPORTANT: Adding both the keydown and keypress events without a comma to delimit them means both may fire simultaneously. This is likely to spawn $rootScope:inprog errors. Adding a comma between them creates a disjunctive, and ensures only only $digest cycle occurs. Couldn't apply the edit since it's only a single character.Arnulfo
this doesn't capture the done event on iOS, I ended up listening to the blur event as wellBooze
@BrianF - great solution. Thanks. You also have to change attrs.ngEnter to attrs.keyBind in the scope.$eval(...) function.Fairchild
Maybe this is a very easy question but, where do you put the doSomething() method?Hypostasize
@RicardoGonzales in your controller.Zeiler
Don't you need to take care of unbinding event on unlink or something?Lydgate
This is perfect for when you have a simple input that isn't part of a form! I agree with @NeilS on not prefixing it with 'ng' though.Couchant
G
202

If you only have one input you can use the form tag.

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

If you have more than one input, or don't want to use the form tag, or want to attach the enter-key functionality to a specific field, you can inline it to a specific input as follows:

<input ng-keyup="$event.keyCode == 13 && myFunc()" ...>
Gorse answered 3/2, 2014 at 18:34 Comment(5)
This is a clever way of doing this without even having to write your own directiveInd
Even shorter: <input ng-keyup="$event.keyCode == 13 && myFunc()"... />Suiter
Works great, I used the ng-keyup directive, but I have one big issue with it, if I only have one text field, he submits the complete form (postback) but I don't want that. I tried already ng-keyup="$event.keyCode == 13 && onTextBoxKeyUp($event)" and in the function "event.preventDefault();", but did not help ;(Cooks
this is shorter but keeping DRY approach in my mind i would still create directive and use it with directive.Demosthenes
This may be problematic depending upon the context - I have a form in which I have two buttons, (wizard like interface), with 'back' and 'next' button, default behaviour on clicking 'enter' key is back button. Now, when using above code, the back button get's CLICKED FIRST, and then myFunction() code is called (which in turns, get's to next part of wizard) So, my wizard goes BACK for a while, and then it goes forward. @EpokK's solution works perfect for me.Schedule
H
34

I wanted something a little more extensible/semantic than the given answers so I wrote a directive that takes a javascript object in a similar way to the built-in ngClass:

HTML

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

The values of the object are evaluated in the context of the directive's scope - ensure they are encased in single quotes otherwise all of the functions will be executed when the directive is loaded(!)

So for example: esc : 'clear()' instead of esc : 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]);
                    });
                }
            });
        };
    }]);
Hardfeatured answered 19/2, 2014 at 13:35 Comment(3)
I get a angluarjs HTML parse error when i try to add a string variable in the function. key-bind="{ enter: 'vm.doTheThing('myVar')' }"How
Also noticed that if i use function with an Object as a variable, the function happens more than once. The code below remove 2+ items when i run this. key-bind="{ enter: 'vm.removeItem(item)' }"How
@How for the first issue, use different types of quotes i.e. 'vm.doTheThing("myVar")'Hardfeatured
P
28

Another approach would be using ng-keypress ,

<input type="text" ng-model="data" ng-keypress="($event.charCode==13)? myfunc() : return"> 

Submit an input on pressing Enter with AngularJS - jsfiddle

Ptisan answered 21/10, 2016 at 5:18 Comment(0)
R
14

Very good, clean and simple directive with shift + enter support:

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);
                       }
                 }
            });
        }
    }
});
Rochellrochella answered 2/2, 2015 at 20:52 Comment(0)
W
5

If you want data validation too

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

The important addition here is $loginForm.$valid which will validate the form before executing function. You will have to add other attributes for validation which is beyond the scope of this question.

Good Luck.

Welloff answered 29/6, 2016 at 2:28 Comment(0)
G
2

Just wanted to point out that in the case of having a hidden submit button, you can just use the ngShow directive and set it to false like so:

HTML

<form ng-submit="myFunc()">
    <input type="text" name="username">
    <input type="submit" value="submit" ng-show="false">
</form>
Gestate answered 5/8, 2016 at 21:43 Comment(2)
+1 <button ng-show="false"></button> is even shorter. No need to set the value of an invisible button.Expansionism
It was my understanding that in order to trigger the ng-submit directive, an input of type="submit" ... I suppose value could be ignored but I believe the former is necessary.Gestate
C
1

Use ng-submit and just wrap both inputs in separate form tags:

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

Wrapping each input field in its own form tag allows ENTER to invoke submit on either form. If you use one form tag for both, you will have to include a submit button.

Compartment answered 18/11, 2014 at 5:25 Comment(0)
G
0

Will be slightly neater using a CSS class instead of repeating inline styles.

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>
Gyasi answered 17/8, 2014 at 10:38 Comment(0)
L
0

FWIW - Here's a directive I've used for a basic confirm/alert bootstrap modal, without the need for a <form>

(just switch out the jQuery click action for whatever you like, and add data-easy-dismiss to your modal tag)

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);
            });
        }
    };
});
Lovell answered 25/5, 2017 at 19:28 Comment(0)
C
0

you can simply bind @Hostlistener with the component, and rest will take care by it. It won't need binding of any method from its HTML template.

@HostListener('keydown',['$event'])
onkeydown(event:keyboardEvent){
  if(event.key == 'Enter'){
           // TODO do something here
           // form.submit() OR API hit for any http method
  }
}

The above code should work with Angular 1+ version

Crossexamine answered 13/8, 2020 at 6:43 Comment(0)
G
0

I focused to below row input in the table

<input ng-keydown="$event.keyCode == 13 && onPressEnter($event)" id="input_0" type="text" >

    $scope.onPressEnter = function (event) {
    let inputId = event.target.id;
    let splited = inputId.split('_');
    let newInputId = 'input' + '_' + ((+splited[1]) + 1);
    if (document.getElementById(newInputId))
        document.getElementById(newInputId).focus();
   // else submit form
}
Gastroscope answered 11/12, 2022 at 7:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.