Creating HTML form is quite easy for developers like us and I’m sure we don’t need to talk it again here since there are plenty of HTML form tutorial out there. Don’t worry we are not going to talk about plain HTML form, we are going to understand form in the context of Angular. Your understanding of plain HTML form will be a prequisite here. This article also requires basic angular knowledge, If you don’t have any idea what angular is, you should read my post on angular overview first before continuing.

The goal of an application is to help people, by using an application people or users want to accomplish their tasks. For example people use browser to surf the internet, people use video player to watch their favorite movies. In order to interact with the application users need a way, and the most common way for users to interact with application is using form. Much of the time you will see form in any web application, taking an example of filling registration step, login, updating your social media, commenting and so on. Form is just everywhere on every web applications.

So, what is AngularJS form?

If you think you have worked often with form, I’m sure you have. But if you’re a self-taught developer who jumps from one tutorial to another, you probably missed a detail or two. In order to understand angular forms, you need to recall the concept of form. Well, I will explain in a simple definition, I hope you will agree with me.

Beforehand, I will explain what control is. Control is a way for user can input data to application, a feature which allows user to control the application. Example of individual control is button, input, textarea, select, etc. Now that we know about controls let’s define a form.

Form is simply a group of controls. So, form is just a collection of related individual controls grouped together and has a meaning, for example login form, meaning a group of control which allows user to input their credential to enter the application.

Angular Form

What is the difference between plain HTML Form and Angular Form? Well, Angular Form is actually just plain HTML Form extended, Angular extends plain HTML Form in some ways. It gives developers more control on how to communicate with the form. Now developer can detect each form’s state since Angular gives state to each of them, such as pristine, dirty, valid, invalid. We’ll discuss each of this state and see it in action later.

Angular form creates an instance of FormController. FormController itself has methods and properties as below.

Angular Form Properties

Form properties also represent its states. The properties are $pristine, $dirty, $valid and $invalid.

formName.$pristine: TRUE if the user has not interacted with the form yet

formName.$dirty: TRUE if the user has already interacted with the form.

formName.$valid: TRUE if all containing form and controls are valid

formName.$invalid: TRUE if at least one containing form and control is invalid.

formName.$error: Is an object hash, containing references to all invalid controls or forms, where: keys are validation tokens (error names) - such as required, url or email), values are arrays of controls or forms that are invalid with given error.



What you see above is the properties or state of the form. You can also checks the state of each individual control by using formName.controlName.$propertyName, for example formName.controlName.$pristine and so on. Note that, formName is simply the value of name attribute you put to the form, while controlName is the value of name attribute of individual control such as the name of input, the name of textarea, etc.

These state of form produces css classes related to corresponding state. Here’s the list of some of css classes:

ng-pristine

ng-dirty

ng-valid

ng-invalid

Each of the css class is appended by Angular to the form or individual control according to its state. For example, if your form has a state of pristine it will also have a ng-pristine class, if your form is invalid, it will have ng-invalid class, the same goes to dirty and valid state. This will make you able to style the form from using css for each different state.

Angular Form Methods

While form properties also available in the individual control, The methods only available for the form, not for individual controls.

formName.$addControl(): register a control with the form

formName.$removeControl(): remove a control from the form

formName.$setDirty(): set the form to Dirty state

formName.$setPristine(): set the form to its pristine state

formName.$setValidity(): set the validity of a form control

Flow of the form states

It is important to understand flow of the form states in order to use angular form properly. This flow gives you visualization of the form state from the very first time the form is rendered until the user has finished filling the form.

Flow 1 : pristine and invalid

When the form is first rendered and the user has not interacted with the form yet.

Flow 2 : dirty and invalid

User has interacted with the form, but validity has not been satisfied, yet.

Flow 3 : dirty and valid

User has finished filling the form and all the validation rule has been satisfied

Form Validation

Now that we have grasped the fundamental of angular form, the states and its flow. We are ready to create something with it. We will implement angular form to create a simple registration form with validation. We want the form to behave like this:

Users must enter their first name, last name and email address, this is simple validation rule we want to achieve.

Inputs will have background color of red if its state are dirty and invalid (flow 2)

Inputs will have background color of green if its state are dirty and valid (flow 3)

Show error message next to control related to error in validation.

Notice that we only concern to flow 2 and flow 3. Since flow 1 simply represents the form before the user interacted with, so we don’t need to do any special styling at this point.

In this exercise we will create three files, index.html which contains our form mark up, script.js which contains the controller and style.css to style the form. Let’s create the index.html first

Listing 1: The form

// index.html <!DOCTYPE html> <html ng-app=""> <head> <title>Angular Form</title> <script type="text/javascript" src="js/angular.min.js"></script> <script type="text/javascript" src="js/script.js"></script> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <div id="container" ng-controller="AppCtrl"> <h1>Simple Registration Form</h1> <form name="appForm" novalidate class="app-form"> <label>First name</label> : <input type="text" name="firstName" ng-model="user.firstName” required><br/> <label>Last name</label> : <input type="text" name="lastName" ng-model="user.lastName" required><br/> <label>Email</label> : <input type="email" name="email" ng-model="user.email" required><br/> <label>Gender</label> : <input type="radio" name="gender" ng-model="user.gender" value="male"> Male <input type="radio" name="gender" ng-model="user.gender" value="female"> Female<br/> <button ng-click="save()">Register</button> </form> <div ng-show="master">{{master | json}}</div> </div> </body> </html>

In index.html, first we load all the required scripts and css file. Then we initialize the whole page as angular application by putting ng-app=”” directive to the html tag. We use a controller named AppCtrl to handle the form.

We give ‘appForm’ as a name for our form, this is important because we want to use this name later to access form properties. The form has ‘novalidate’ directive which disable the browser default validation method. To store data from each form control we use ‘user’ model, we populate the model to individual control according to model properties, such as user.firstName, user.lastName, user.email, user.gender. This model available in our controller. We also give each control a name according to its model like fistName, lastName, so on. This is also important because we want to access individual control state later when validating the data. We want our users to input their firstname, lastname and email address thus we must make the input required, to do this simply put ‘required’ directive to the related controls. And this is the simple validation rule we want.

The next thing we want to do is to style each form control according to its state. Now, write some css rules to style.css

Listing 2: Styling the form with CSS

// style.css .app-form .ng-dirty.ng-invalid{ background: red; } .app-form .ng-dirty.ng-valid{ background: lightgreen; }

The code above contains styling rule for flow 2 and flow 3. Remember that each state produce css class related to it, so flow 2 which is dirty and invalid state produces css class of ng-dirty and ng-invalid. In the style.css we target our first rule to match element (i.e control) which has both classes of flow 2 (ng-dirty and ng-invalid) and give a red background to it. The same goes to flow 3, recall that flow 3 has state of dirty and valid so we target element that has class of ng-dirty and ng-valid. app-form is the class of the form.

We have satisfied 3 points in our exercise plan, the last thing we want to achieve is showing an error message indicating what error the user encounter. To do that we are going to bind to the form control state, in other words we will check or read the property or state of the form. This is why I said naming is important, to access individual control state we use formName.controlName.$property, so in our index.html to checks if a firstName control is dirty we use appForm.firstName.$dirty. This will return true if it is dirty. The idea of our error message is to show a span containing a message if a control is dirty and have an error or invalid. If it is invalid but pristine, hide the span because user has not interacted with it yet. To control hiding and showing of the span we use ‘ng-show’ directive. Please consider the following updated index.html

Listing 3: Error message handling

<!DOCTYPE html> <html ng-app=""> <head> <title>Angular Form</title> <script type="text/javascript" src="js/angular.min.js"></script> <script type="text/javascript" src="js/script.js"></script> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <div id="container" ng-controller="AppCtrl"> <h1>Simple Registration Form</h1> <form name="appForm" novalidate class="app-form"> <label>First name</label> : <input type="text" name="firstName" ng-model="user.firstName" required> <span ng-show="appForm.firstName.$dirty && appForm.firstName.$error.required">Required: Tell us your first name</span> <br/> <label>Last name</label> : <input type="text" name="lastName" ng-model="user.lastName" required> <span ng-show="appForm.lastName.$dirty && appForm.lastName.$error.required">Required: Tell us your last name</span> <br/> <label>Email</label> : <input type="email" name="email" ng-model="user.email" required> <span ng-show="appForm.email.$dirty && appForm.email.$error.required">Required: Tell us your email address</span> <span ng-show="appForm.email.$dirty && appForm.email.$error.email">Invalid: This is not a valid email address</span> <br/> <label>Gender</label> : <input type="radio" name="gender" ng-model="user.gender" value="male"> Male <input type="radio" name="gender" ng-model="user.gender" value="female"> Female<br/> <button ng-click="save()">Register</button> </form> <div ng-show="master">{{master | json}}</div> </div> </body> </html>

In this updated index.html I have appended a span containing error message related to each required control. We have known how to checks a state of control, now we need to know how to check if a control has an error. We do this similar to check a state of control, the format is formName.controlName.$error.nameOfError, for example to check if a control has an error related to email format, we write in our index.html as following appForm.email.$error.email. If we want to check if email has not been filled or left empty we write appForm.email.$error.required. So to display the message of email we put the following codes

<span ng-show=”appForm.email.$dirty && appForm.email.$error.required”> Required: Tell us your email!</span>

This span will show if user has interacted with email input (dirty state), but then leave it empty (remember that email is required). But what if we want to display error message indicating that user has entered an invalid email address format, we’ll simply copy above code and modify the ng-show value to be “appForm.email.$dirty && appForm.email.$error.email”, this will return show the message if the user entered an invalid email address. This goes similarly to other control, to show error message in the first name field we put this code.

<span ng-show=”appForm.firstName.$dirty && appForm.firstName.$error.required”> Required: Tell us your first name!</span>

We also have a controller in script.js which contains a little code to declare models for first time and to do something to display the data, it is beyond the form discussion so you can skip it. And here it looks like:

Listing 4: AppCtrl controller

// script.js function AppCtrl($scope){ $scope.user = null; $scope.master = null; $scope.save = function(){ $scope.master = angular.copy($scope.user); } }

Conclusion

To use angular form maximaly you must understand form and control states, its flow of state and how to take benefit from those. You can use binding to display an error message or you can style individual control according to each state since angular produces css classes for each form and control state.