← all articles

Form validation with AngularJS

Tamas Piros | 19 January 2016 | AngularJS

HTML5 form validation attributes

Before we get to the Angular bit of the discussion let's also discuss what form validation features HTML5 comes with out of the box. There are the following attributes that can be used on <input> elements:

  • required: a standard HTML5 attribute to the form and it makes our field compulsorily to fill out
  • email: We can also validate an input field and see if the entered detail is an email address. In order to achieve this we need to set the input’s type value to ‘emai’.
  • number: Similarly to e-mail, if we would like to check that the input value is a number, we need to change the input type value to ‘number’
  • url: Changing the input type field to URL will result in our input text being checked to be a valid URL.

Angular form validation attributes

There are of course AngularJS specific form validation attributes as well. These include options to check against the length of the input field as well as a particular pattern. Let’s take a look at these now:

  • ng-minlength: This directive enforces the minimum length of the input, it accepts a number as a parameter and that number is going to be our minimum length that’s require to successfully fill out this field
  • ng-maxlength: his directive accepts a number again as its parameber and it allows us to specify the maximum input size for a particular field
  • ng-pattern: With the ng-pattern directive we can specify a regular expression that will enforce us to enter values defined using this pattern
  • custom: you can of course also add custom attributes to check for errors.

Form status and capturing errors

Now that we know how to add validation to our form, we of course need to make sure that we capture the potential errors coming from the validation and we handle those and display some messages to the users for example.

In order to achieve this we need to discuss one more thing – the fact that how AngularJS adds properties to forms which enable us to see changes about our form on the fly, without having to wait for the user to submit the form. (We can of course make our validation on form submit as well, more on that later).

We have seen before that Angular utilises properties from the $scope object and when it comes to form validation angular actually attaches properties to our form automatically which we can retrieve and check against – and also, there will be CSS classes created that we can modify to suit our needs.

$pristine and $dirty

When we first load our form it’ll be attached a value that we can access by looking at the $pristine value - $pristine is going to be set to true if there are no modifications to the form and false if the the form has been modified. It’s worth to note that this true/false value is regardless of the the other authentication methods. The CSS class attached to the form is .ng-valid.

Another Boolean value that gets set regardless of the validation requirements is $dirty. This property becomes true when the user has modified the form. In other words, the $dirty property is going to be set to true even though another specified validation is not correct. The CSS class attached to the form is called .ng-dirty.

Now that we discussed these two properties that don’t actually care whether the input data in the form is correct or not, they only care about the overall form and it’s state, let’s have a look at the properties that can check validity. There are two such properties: $valid is set to true when the all the validation has plassed and we also have access to a CSS property, namely, .ng-valid.

It goes without saying that the property $invalid is set to true when the form has not passed a particular validation requirement and with that we can also access a CSS property called .ng-invalid.

Finally we also get access to an object containing all the validation properties – this object is called $error.

ng-submit and ng-click

This gives us enough information on how to handle form validation but there’s one more thing that we need to look at. As I have mentioned before AngularJS gives us a great set of built in properties that we can work with and determine whether a particular form is in a valid state or if it has been touched at all. Once we have the validation out of the way we of course arrive to the next step: we would like to send that data off somewhere, or we just want to process the data. There are two built-in directives that come to our aid, ng-submit and ng-click. Both of these directives allow us to specify JavaScript methods that need to be invoked when someone presses the submit buttons.

Example form

<!DOCTYPE html>
    <html ng-app>
    <meta charset="utf-8">
    <title>My first Angular app</title>
        <p>Enter a new rebel member: </p>

        <form name="myform">
            <p>Name: <small>(Min 3 Max 25 chars)</small> <input type="text" ng-minlength=3 ng-maxlength=25 required ng-model="rebel.name" name="name">
            <div ng-show="myform.name.$dirty && myform.name.$invalid">
                <p ng-show="myform.name.$error.required">This field is required</p>
                <p ng-show="myform.name.$error.minlength">Minimum length is 3 chars</p>
                <p ng-show="myform.name.$error.maxlength">Maximum length is 25 chars</p>
            <p>Age: <small>(Only integer)</small><input type="text" ng-pattern="/^[0-9]{2,3}$/"  ng-model="rebel.age" name="age">
                <div ng-show="myform.age.$dirty && myform.age.$invalid">
                <p ng-show="myform.age.$error.pattern">Two or three digit integers please</p>

    <script src="angular.js"></script>

In the example above we are creating a form that allows users to enter information about Star Wars rebels (just to continue with the previous Rebels database example). We have two input fields and the first input accepts anything between 3 and 25 characters – ng-minlength is set to 3 while ng-maxlength is set to 25. As we can see the second input field accepts only integers and we have specified that using the ng-pattern directive. Of course, we could have written <input type=”number”> as opposed to using a text field in conjunction with the directive but I wanted to show you this functionality as well.

We are also utilising the ng-show directive for <p> elements to show/hide error messages. As we can see the paragraphs with the error message are inside a <div> element that also has an ng-show directive associated with it. The <div> itself is only going to be displayed if the form’s $dirty property is true – that is, someone has modified anything inside the form – and when the $invalid property is set to true as well – meaning that one of the two validations is incorrect.

$error object

We have talked about the $error object that contains all the errors that we can encounter during a form validation and we use the various properties on the $error object to hide/show the <p> tags. For the first input we have access to three properties from the $error object - $error.required, $error.minlength and $error.maxlength. Based on whether these values are true or false the paragraphs will be displayed. A similar approach is also put in place for the second input box whereby we display the paragraph if the $error object’s pattern property is set to true.

The example above is fairly good to showcase to form validation but of course we can make it much better. First of all we have already briefly mentioned the various CSS classes that we can access – let’s put those into action now. Extend the above example by adding a <style> section just after the <title> tag:

        input.ng-invalid.ng-dirty {
            border: 1px solid red;
        input.ng-valid.ng-dirty {
            border: 1px solid green;

This will tell our application to apply these two styles onto any input elements that have been modified (ng-dirty) and baed on their validity/invalidity apply the appropriate border colours. If we refresh our application in the browser after adding these two lines, you’ll see that no styling is applied to the input boxes. (If you’re curious, remove the .ng-dirty class from the styling and notice how the first input will have a red border already – that is because the input loads up with an empty value we defined ng-minlength to be 3.)

Once you start typing into the fields the right CSS classes will be invoked – go ahead and try this out.

Making the validation less intrusive

So far so good, but I think you have noticed that this validation is a bit too intrusive. The error message pops up as soon as the user starts to type and this is probably not the best method. Let’s change our validation to be invoked when the user submits the form. In order to achieve this there are a few things that we need to change.

First of all, we need to create a controller and using the $scope object, create a function that handles the form submission. (For the time being this will only log a statement to our console as opposed to do anything with the data.)

We also need to add the ng-submit or ng-click directive to the form – we can either add ng-submit as an attribute to our form element or we can add the ng-click directive to a form as an attribute. As we are submitting the form, let’s stick to adding ng-submit.

In light of this, first let’s modify our code and add the necessary controller, function and directive and then let’s modify our code to only do validation once the form has been submitted. Before we get started with ng-submit we need to of course add a controller and attach our method to the $scope object – add the following the the previous example right after the closing </style> tag:

        function MyController($scope) {
            $scope.add = function() {
                console.log($scope.rebel.name + " added to the database.");

The next thing is to add the controller and ng-submit to our application. Modify the<div> element right after the <body> element and include the ng-controller directive:

    <div ng-controller="MyController">

And finally modify the <form> element as well to add the ng-submit directive and specify the previously created function’s name to call on the submit event:

    <form name="myform" ng-submit="add()">

And a submit button as well:

    <button type=”submit”>Add rebel</button>

Go ahead and test the application. To monitor whether our function is working correctly you need to open your browser’s developer toolbar where you can access the JavaScript log. It should display a message with the rebel’s name coming from the console.log() statement that we have implemented above.

As you probably have noticed the functionality is the same in terms of the validation, so let’s modify this behaviour as well.

If you think about this for a minute, what we are trying to achieve is to have a value ‘submitted’ that we would ideally like to check the form’s state against. As we have discussed before using the $scope objects and its properties is an ideal way to initialise values to our application therefore we can setup an ‘isSubmitted’ boolean value inside our controller, and we can also utilise the value coming from this Boolean value as part of the ng-show directives when displaying the validation error messages. In order to achieve this functionality, let’s modify our controller:

        function MyController($scope) {
            $scope.isSubmitted = false;
            $scope.add = function() {
                if ($scope.myform.$valid) {
                    console.log($scope.rebel.name + " added to the database.");
                } else {
                    $scope.isSubmitted = true;

Now that we have access to the isSubmitted boolean variable and it’s available to us we can modify the ng-show directives to read:

    <div ng-show="myform.name.$dirty && myform.name.$invalid && isSubmitted">

If you go ahead and try out the application you will notice that the <div> elements displaying the error messages appear only when you have submitted the form.

Free email mini-course on
Full Stack development

Sign up now to receive a free email mini-course covering the MEAN stack and more. Also be the first to know when we release new courses and videos.