I'm writing a simple login form using angularjs with some client side input validation to check that the user name and password is not empty and longer than three characters. See the below code:

<form name="loginform" novalidate ng-submit="login.submit()" class="css-form">
    <fieldset>

        <div class="control-group input-prepend">
            <span class="add-on"><i class="icon-user"></i></span>
            <input type="text" ng-model="login.username" name="username" required ng-minlength="3" placeholder="username" />
        </div>

        <div class="control-group input-prepend">
            <span class="add-on"><i class="icon-lock"></i></span>
            <input type="password" ng-model="login.password" name="password" required ng-minlength="3" placeholder="" />
        </div>

        <div class="control-group">
            <input class="btn" type="submit" value="Log in">
        </div>

    </fieldset>
</form>

And the controller:

var controller = function($scope) {

    $scope.login = {
        submit: function() {

            Console.info($scope.login.username + ' ' + $scope.login.password);
        }
    }

};

The problem is that the login.submit function will be called even if the input is not valid. Is it possible to prevent this behaviour?

As a side note I can mention that I use bootstrap and requirejs as well.

share|improve this question
    
    
can we use it without form tag and still form.valid would work on ng-click ! – Rizwan Patel Apr 14 '16 at 6:04
up vote 285 down vote accepted

You can do:

<form name="loginform" novalidate ng-submit="loginform.$valid && login.submit()">

No need for controller checks.

share|improve this answer
8  
This should be the accepted answer. No need to check anything in the controller – Howie Feb 12 '14 at 11:22
9  
I disagree with "no need for controller checks". What if we ant additional validation checks happen in the submit function. – b1tsh1ft Jul 31 '14 at 18:42
5  
Perform the additional validation in the directive. Update the validation with $setValidity. – TMB Oct 12 '14 at 22:55
    
@b1tsh1ft It would be preferable to have the current state of the validation be always known rather than figured out on submit. That's kinda the whole point of angular's validation. You can't have any visual indication of an invalid state when the scope doesn't know about it. – Kevin Beal Mar 25 '15 at 18:37
1  
I have tried this approach, but it seems that it evaluates both (i.e. it does not short circuit the boolean after the && I have tried passing in the value as part of the submit and confirmed that the value itself is "false" – Archimedes Trajano Mar 7 '16 at 1:52

Change the submit button to:

<button type="submit" ng-disabled="loginform.$invalid">Login</button>
share|improve this answer
1  
Great answer. You rock! – Harsha.Vaswani Mar 11 '15 at 13:30
3  
This should be the accepted answer really. – Red Sep 7 '15 at 13:45
14  
You can still submit the form if you press enter while an input field has the focus! – fabsenet Oct 20 '15 at 14:28
2  
@Red: See comment above. – Andrei Rînea Nov 17 '15 at 20:16
1  
@AndreiRînea very good point. I agree, that is a huge issue. – Red Nov 18 '15 at 13:38

So the suggested answer from TheHippo did not work for me, instead I ended up sending the form as a parameter to the function like so:

<form name="loginform" novalidate ng-submit="login.submit(loginForm)" class="css-form">

This makes the form available in the controller method:

$scope.login = {
    submit : function(form) {
        if(form.$valid)....
    }
share|improve this answer
    
I had the same issue. Using your method worked, though. – Panda4Man Dec 8 '14 at 16:59

Your forms are automatically put into $scope as an object. It can be accessed via $scope[formName]

Below is an example that will work with your original setup and without having to pass the form itself as a parameter in ng-submit.

var controller = function($scope) {

    $scope.login = {
        submit: function() {
            if($scope.loginform.$invalid) return false;

        }
    }

};

Working example: http://plnkr.co/edit/BEWnrP?p=preview

share|improve this answer
4  
How would you access the form if you use "As Controller" notation instead of $scope? – masimplo Dec 18 '13 at 12:08
    
@masimakopoulos: You can simply use if(this.loginform.$invalid).. instead but then in the HTML you have to give the form the name <form name="ctrl.loginform" ... And that's assuming you're using <div ng-controller="controller as ctrl".. in your controller-as syntax. Thanks @JoshCaroll – Bart Oct 14 '15 at 13:32

HTML:

<div class="control-group">
    <input class="btn" type="submit" value="Log in" ng-click="login.onSubmit($event)">
</div>

In your controller:

$scope.login = {
    onSubmit: function(event) {
        if (dataIsntValid) {
            displayErrors();
            event.preventDefault();
        }
        else {
            submitData();
        }
    }
}
share|improve this answer
    
is it really necessary to do the check within the onsubmit method? This will mean you have to check that input meets all criteria both in the markup(via angular) and in the js code. In my opinion angular should not call the onsubmit when the input is invalid. see benlesh.com/2012/11/angular-js-form-validation.html saying "ng-submit cannot be called until the entire form is $valid" – Runar Halse Apr 28 '13 at 14:59
    
You could also disable the button to not allow submission if form is valid. You could also use the form an ng-submit. If angular does not handle form validation then event.preventDefault() is the way to go, to stop form submission. – TheHippo Apr 28 '13 at 18:03
    
@RunarHalse It is really necessary to do the check. I agree with you that it should not be this way. The reason that the onsubmit method is not called in the example that you linked is because that example does not have novalidate set. The browser is preventing the events from raising, not Angular. Here is his example w/ nobalidate on: plnkr.co/edit/R0C8XA?p=preview. Notice the form submits. – davidmdem Aug 13 '13 at 21:32
3  
This doesn't work if you press enter to submit the form. – Hengjie Sep 8 '13 at 15:13
    
perfect just what i was looking for, a way to block form submit using angular – setebos Nov 14 '13 at 11:20

Just to add to the answers above,

I was having a 2 regular buttons as shown below. (No type="submit"anywhere)

<button ng-click="clearAll();" class="btn btn-default">Clear Form</button>
<button ng-disabled="form.$invalid" ng-click="submit();"class="btn btn-primary pull-right">Submit</button>

No matter how much i tried, pressing enter once the form was valid, the "Clear Form" button was called, clearing the entire form.

As a workaround,

I had to add a dummy submit button which was disabled and hidden. And This dummy button had to be on top of all the other buttons as shown below.

<button type="submit" ng-hide="true" ng-disabled="true">Dummy</button>

<button ng-click="clearAll();" class="btn btn-default">Clear Form</button>

<button ng-disabled="form.$invalid" ng-click="submit();"class="btn btn-primary pull-right">Submit</button>

Well, my intention was never to submit on Enter, so the above given hack just works fine.

share|improve this answer

Although not a direct solution for the OPs question, if your form is within an ng-app context, but you want Angular to ignore it altogether, you can do this explicitly using the ngNonBindable directive:

<form ng-non-bindable>
  ...
</form>
share|improve this answer

I know this is an old thread but I thought I'd also make a contribution. My solution being similar to the post already marked as an answer. Some inline JavaScript checks does the trick.

ng-click="form.$invalid ? alert('Please correct the form') : saveTask(task)"
share|improve this answer
1  
You can still submit the form if you press enter while an input field has the focus! – Yevgeniy Afanasyev Dec 18 '15 at 2:26

I know it's late and was answered, but I'd like to share the neat stuff I made. I created an ng-validate directive that hooks the onsubmit of the form, then it issues prevent-default if the $eval is false:

app.directive('ngValidate', function() {
  return function(scope, element, attrs) {
    if (!element.is('form'))
        throw new Error("ng-validate must be set on a form elment!");

    element.bind("submit", function(event) {
        if (!scope.$eval(attrs.ngValidate, {'$event': event}))
            event.preventDefault();
        if (!scope.$$phase)
            scope.$digest();            
    });
  };
});

In your html:

<form name="offering" method="post" action="offer" ng-validate="<boolean expression">
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.