45

I am building an angular app for which I have some forms set up. I have some fields that are required to be filled before submission. Therefore I have added 'required' on them:

<input type="text" class="form-control" placeholder="Test" ng-model="data.test" required>

However when I launch my app, the fields are displayed as 'invalid' and the classes 'ng-invalid' and 'ng-invalid-required' even before the submit button has been click or before the user has typed anything in the fields.

How can I make sure that thoses 2 classes are not added immediately but either once the user has submitted the form or when he has typed something wrong in the corresponding field?

Nick Div
  • 5,338
  • 12
  • 65
  • 127
Spearfisher
  • 8,445
  • 19
  • 70
  • 124

5 Answers5

92

Since the inputs are empty and therefore invalid when instantiated, Angular correctly adds the ng-invalid class.

A CSS rule you might try:

input.ng-dirty.ng-invalid {
  color: red
}

Which basically states when the field has had something entered into it at some point since the page loaded and wasn't reset to pristine by $scope.formName.setPristine(true) and something wasn't yet entered and it's invalid then the text turns red.

Other useful classes for Angular forms (see input for future reference )

ng-valid-maxlength - when ng-maxlength passes
ng-valid-minlength - when ng-minlength passes
ng-valid-pattern - when ng-pattern passes
ng-dirty - when the form has had something entered since the form loaded
ng-pristine - when the form input has had nothing inserted since loaded (or it was reset via setPristine(true) on the form)
ng-invalid - when any validation fails (required, minlength, custom ones, etc)

Likewise there is also ng-invalid-<name> for all these patterns and any custom ones created.

Neoheurist
  • 3,183
  • 6
  • 37
  • 55
Ryan Q
  • 10,273
  • 2
  • 34
  • 39
  • 4
    @Ryan Q - But this causes problem while using screen readers (NVDA screen reader in my case) - It shouts 'Invalid entry' as soon as the field is focused. – Kumar Sambhav Sep 11 '15 at 09:42
  • That's interesting Kumar for screen readers. I'm curious is this because of Angular's controller validation setters or because of the simple red color on an input? – Ryan Q Nov 17 '15 at 21:01
  • Hello your fix is bad, since user do not depend of CSS to submit or do not submit the form, so with this developer must do a check before send result to anywhere, or setup a boolean on each input (modelchange) –  Jan 31 '19 at 16:56
8

Thanks to this post, I use this style to remove the red border that appears automatically with bootstrap when a required field is displayed, but user didn't have a chance to input anything already:

input.ng-pristine.ng-invalid {
    -webkit-box-shadow: none;
    -ms-box-shadow: none;
    box-shadow:none;
}
user2344489
  • 91
  • 1
  • 3
2

Since the fields are empty they are not valid, so the ng-invalid and ng-invalid-required classes are added properly.

You can use the class ng-pristine to check out whether the fields have already been used or not.

Minko Gechev
  • 25,304
  • 9
  • 61
  • 68
  • Tutorial link is dead. – Max Jul 15 '15 at 22:35
  • Thanks for the comment. You can deploy `ng-tutorial` from here https://github.com/mgechev/ng-tutorial – Minko Gechev Jul 16 '15 at 13:46
  • I believe the question is less about right or wrong, but about UX. It is a horrible experience to open a form with all of it red, and that is Angular s default. Is an initial state invalid? Yes. Is it friendly to show all red? No. – Tiago B Dec 22 '20 at 18:16
1

The following method is for old AngularJS:

Try to add the class for validation dynamically, when the form has been submitted or the field is invalid. Use the form name and add the 'name' attribute to the input. Example with Bootstrap:

<div class="form-group" ng-class="{'has-error': myForm.$submitted && (myForm.username.$invalid && !myForm.username.$pristine)}">
    <label class="col-sm-2 control-label" for="username">Username*</label>
    <div class="col-sm-10 col-md-9">
        <input ng-model="data.username" id="username" name="username" type="text" class="form-control input-md" required>
    </div>
</div>

It is also important, that your form has the ng-submit="" attribute:

<form name="myForm" ng-submit="checkSubmit()" novalidate>
 <!-- input fields here -->
 ....

  <button type="submit">Submit</button>
</form>

You can also add an optional function for validation to the form:

//within your controller (some extras...)

$scope.checkSubmit = function () {

   if ($scope.myForm.$valid) {
        alert('All good...'); //next step!
          
   }
   else {
        alert('Not all fields valid! Do something...');
    }

 }

Now, when you load your app the class 'has-error' will only be added when the form is submitted or the field has been touched. Instead of:
!myForm.username.$pristine

You could also use:
myForm.username.$dirty

FOR NEW ANGULAR 2+

This based on Bootstrap 5.3 and Angular 15/16, could be changed in future.

<div class="form-group">
  <label>Password</label>
  <input type="password" formControlName="password" class="form-control" [ngClass]="{'is-invalid': password?.errors != null}">
</div>

the component form, make sure that you have change the myForm, into form variable you need.

  get password() { return this.myForm.get("password") }
Skulaurun Mrusal
  • 2,792
  • 1
  • 15
  • 29
grindking
  • 917
  • 5
  • 13
  • 29
-2

the accepted answer is correct.. for mobile you can also use this (ng-touched rather ng-dirty)

input.ng-invalid.ng-touched{
  border-bottom: 1px solid #e74c3c !important; 
}
Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
shakirthow
  • 1,356
  • 14
  • 15
  • 7
    The `ng-touched` class means the field has been blurred, it has nothing to do with mobile. – jrista Dec 10 '15 at 02:19