AngularJS forms validation

The AngularJS support for form validation is based on directives that replace the standard HTML elements like form and input.

You don’t have to do anything to use the directives for form elements. AngularJS applies them automatically when it encounters form, input, select, and textarea elements. The directives provide AngularJS features for forms seamlessly, and there are some additional attributes available to enhance the development experience.

When AngularJS encounters a form element, it automatically sets up the basic features that we discuss later. There are some attributes you must set on the form element to get the best results from AngularJS form validation. The first is the name attribute; the directive that replaces the form element defines some useful variables that report on the validity of the form data and accesses these values via the value of the name property(we will see them later).

<form name="myForm" novalidate ng-submit="addUser(newUser)">

To disable the browser validation support and enable the AngularJS features, you have to add the novalidate attribute to form element, which is defined by the HTML5 specification and tells the browser not to try to validate the form itself, allowing AngularJS to work unhindered.

The last addition to the form is ng-sumbit directive. This directive specifies a custom response to a submit event, which is triggered when the user submits the form.

The next step is to apply the standard HTML validation attributes to the input elements. Here is one of the input elements from the example:

<div class="form-group">
    <label>Email:</label>
    <input name="userEmail" type="email" class="form-control" required ng-model="newUser.email">
</div>

Just as with the form element, it is important to add a name attribute to the individual elements that you want to validate so that you can access the special variables that AngularJS provides. The other attributes I highlighted in the listing tell AngularJS what kind of validation I want. The type attribute specifies the data type that the input element will gather, which is email in this case.

HTML5 defines a new set of type attribute values for input elements, and the ones that AngularJS can validate are shown below.

checkbox – Creates a check box (pre-dates HTML5)
email – Creates a text input that accepts an e-mail address (new in HTML5)
number – Creates a text input that accepts a number address (new in HTML5)
radio – Creates a radio button (pre-dates HTML5)
text – Creates a standard text input that accepts any value (pre-dates HTML5)
url – Creates a text input that accepts a URL (new in HTML5)

Monitoring the Validity of the Form

The directives that AngularJS uses to replace the standard form elements define special variables that you can use to check the validation state of individual elements or the form as a whole. Here is the list of them:

$pristine – Returns true if the user has not interacted with the element/form
$dirty – Returns true if the user has interacted with the element/form
$valid – Returns true if the contents of the element/form are valid
$invalid – Returns true if the contents of the element/form are invalid
$error – Provides details of validation

These variables can be used in combination to present the user with feedback about validation errors. We will see how to do this later in this post.

Providing validation feedback

Each time the user interacts with an element that is being validated, AngularJS checks its state to see whether it is valid. The validity checks depend on the element type and how it has been configured. AngularJS reports on the outcome of these validation checks by adding and removing the elements it validates from a set of classes, which can be combined with CSS to provide feedback to the user by styling the element.

The are four basic classes:
ng-pristine – Elements that the user has not interacted are added to this class.
ng-dirty – Elements that the user has interacted are added to this class.
ng-valid – Elements that are valid are in this class.
ng-invalid – Elements that are not valid are in this class.

Let’s see how we can use these classes;

<!DOCTYPE html>
<html ng-app="exampleApp">

<head>
  <title>Forms</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
  <script>
    angular.module("exampleApp", [])
      .controller("defaultCtrl", function($scope) {
        $scope.addUser = function(userDetails) {
          $scope.message = userDetails.name + " (" + userDetails.email + ") (" + userDetails.agreed + ")";
        }

        $scope.message = "Ready";
      });
  </script>
  <style>
    form .ng-invalid.ng-dirty {
      background-color: lightpink;
    }
    
    form .ng-valid.ng-dirty {
      background-color: lightgreen;
    }
    
    span.summary.ng-invalid {
      color: red;
      font-weight: bold;
    }
    
    span.summary.ng-valid {
      color: green;
    }
  </style>
</head>

<body>
  <div id="todoPanel" class="panel" ng-controller="defaultCtrl">
    <form name="myForm" novalidate ng-submit="addUser(newUser)">
      <div class="well">
        <div class="form-group">
          <label>Name:</label>
          <input name="userName" type="text" class="form-control" required ng-model="newUser.name">
        </div>
        <div class="form-group">
          <label>Email:</label>
          <input name="userEmail" type="email" class="form-control" required ng-model="newUser.email">
        </div>
        <div class="checkbox">
          <label>
            <input name="agreed" type="checkbox" ng-model="newUser.agreed" required> I agree to the terms and conditions
          </label>
        </div>
        <button type="submit" class="btn btn-primary btn-block" ng-disabled="myForm.$invalid">OK</button>
      </div>
      <div class="well">
        Message: {{message}}
        <div>
          Valid:
          <span class="summary" ng-class="myForm.$valid ? 'ng-valid' : 'ng-invalid'">
              {{myForm.$valid}}
          </span>
        </div>
      </div>
    </form>
  </div>
</body>

</html>

I have defined four CSS styles that select elements that belong to the classes I listed above. The first two styles select elements that are members of the ng-dirty class, which is applied to elements only after the user has interacted with them.(Before the interaction, elements are members of the ng-pristine class.) Elements that have valid content are members of the ng-valid class and are shaded a light green color. Elements that have invalid content are members of the ng-invalid class and are shaded in light pink. Combining the ng-valid and ng-valid classes with ng-dirty in the CSS selector means that the real-time feedback about element validity doesn’t begin until the user starts interacting with the element.

You can check the code that I posted above in the Plunker .

In addition AngularJS adds elements to classes to give specific information about each of the validation constraints that apply on an element. The name of the class is used based on the corresponding attribute. For example

form .ng-invalid-required.ng-dirty { background-color: lightpink; }
form .ng-invalid-email.ng-dirty { background-color: lightgoldenrodyellow; }

These styles are applied to specific validation cases.

Using the Special Variables to Provide Feedback

To see how provide real-time validation feedback modify the existing code:
- add to the styles block following css rule

div.error {color: red; font-weight: bold;}

- right after the email input add following code

<div class="error" ng-show="myForm.userEmail.$invalid && myForm.userEmail.$dirty">
  <span ng-show="myForm.userEmail.$error.email">Please enter a valid email address</span>
  <span ng-show="myForm.userEmail.$error.required">Please enter a value</span>
</div>

You will notice that when you modify email input the validation message appears below the field(if field is invalid of course).

Validation Attributes

The directive that AngularJS uses for input elements provides some additional attributes that can be used to improve integration with the data model. These attributes are available only when the input element does not have a type attribute or when the type attribute is text, url, email, or number.

ng-model – Specifies a two-model binding, as described earlier in this chapter
ng-change – Specifies an expression that is evaluated when the contents of the element are changed, as described in Chapter 11
ng-minlength – Sets a minimum number of characters required for the element to be valid
ng-maxlength – Sets a maximum number of characters required for the element to be valid
ng-pattern – Sets a regular expression. The contents of the element must match this pattern in order to be valid
ng-required – Sets the value of the required attribute with a data binding

The following example I took from the nice book called Pro AngularJS(Expert’s Voice in Web Development) by Adam Freeman. I recommend to read this book to everyone who wants to learn AngularJS.

Share this post:Tweet about this on TwitterShare on Facebook0Share on LinkedIn0Share on Google+0Share on Reddit0Email this to someoneDigg this