Angular Tutorial – Part 6: Building and Validating Data Entry Forms

In this article we will look at how we can build data entry forms with proper validation techniques in angular. We will also look at how the controller should handle the data entry forms and propagate the data to the respective business logic components i.e. services.


Link to complete series

  1. Angular Tutorial – Part 1: Introduction to Angular.js
  2. Angular Tutorial – Part 2: Understanding Modules and Controllers
  3. Angular Tutorial – Part 3: Understanding and using Directives
  4. Angular Tutorial – Part 4: Understanding and implementing Filters
  5. Angular Tutorial – Part 5: Understanding and implementing Services
  6. Angular Tutorial – Part 6: Building and Validating Data Entry Forms
  7. Angular Tutorial – Part 7: Understanding Single page applications and Angular routing

Background

Whenever we talk about data entry forms, the first thing that comes to mind is how we will be handling the user data in the business logic and how will we ensure that the proper data is being passed in the application. In this article our main focus will be to look at how the controller should handle the data coming from views and how we can use angular ng-form directive to create better data entry forms.

Using the code

Let us start the discussion by building a simple form that will accept the book as input. later we can use the same form for creation of a new book entity in the system and updating and existing book in the system.

Angular1_01

Understanding the ngForm directive

The above image shows the vanilla HTML needed to implement the form. We are using bootstrap for styling the form. Let before we could proceed, we first need to understand how this form will behave as a directive when it is put inside an angular application. Actually what happens is that if we put a form tag inside out angular application, angular automatically replaces the default form with its own form directive. This way just by putting our form on the page, we have all the functionality of angular form directive( ngForm) available to us.

One question that often creep up after knowing this fact is that why angular does that and puts its own form directive instead of our vanilla HTML form. The answer to this question is that firstly, the vanilla HTML forms are designed to do a full page postback to the server whenever it is being submitted. We can prevent that ourselves using custom code but angular directive takes care of preventing this behaviour. However for some obscure reasons if we still want our angular form to perform a full page postback, that can also be done just by specifying the action attribute in our form. But perhaps that is not needed for most client side apps.

The second reason angular does this is to provide us loads of features that we can use in our app. One functionality is the availability of ngSubmitand ngClickdirective. These directives can be used to wire up our functions on form submit or on click of a submit button in form. Another feature and perhaps a very useful one is that angular provides various states for all the form elements contained in the form. These states are very helpful when it comes to validating our form before submission. We will look at these states and form submission at a later point in this article. For now its suffice to say that whenever we are putting a form tag on the page, we are actually using a full featured and action packed ngForm directive.

Updating the Service

before we could go and create the forms to create or update the book entity, lets update our localBookServiceto be able to handle the create and edit requests. Following code shows how the service implements the create and edit functions.

Controller support Create and Edit

Next thing we need to do is to have the $scope objects to keep track of the item being added and removed from the view. We also need functions to get the value from the view and calling the appropriate service function. Lets look at the controller code and try to understand what is happening.

What we have done in our controller is that we have created a $scope.book object that will keep track of the book that is being added from the view. This object will be bound to a form and when the form gets submitted, we will call the $scope.addBook which in turns save this book item into the list using our service class.

To be able to update a book entity, first we need an object to keep track of which book is being updated by the user so we create [crayon inline=”true” ]scope.editBook[/crayon]. Then we let the user an option to select which book he want to update and what should be done if he cancels the update. So we created the $scope.setEditBookwhich will use the user selected book as $scope.editBook. The cancel on the other hand will reset $scope.editBook to null.

If we take a closer look at the $scope.setEditBookwe can see that we are using angular.copymethod inside. The reason for doing this is that we don’t want the dirty values to get into our book list so we create a copy if the original object selected by the user. When user chose to update, we will use this copy object to update the actual list. This approach makes it easier to not let the invalid changes propagate to actual model. Since we are working on a copy object, if the values are invalid then we can chose to ignore the update or let the user know that they are invalid and need to be fixed.

Note: Having an object copy for edit operation is recommended for edit and update scenarios as it reduces the chances to having the invalid values being propagated to the server.

Now that we have all the code needed to perform the actual operations, lets get to the topic at hand and create our forms.

Creating a book Entity

Lets use the same form that we looked at earlier and use that to create a book entity. First thing we need to do is to bind all the $scope.book properties with the respective UI elements. Also the submit needs to be wired up with the addBooksfunction. Lets see how this will look.

Angular1_02

Now when we run the application it will look like following.

Angular1_03

Now we have everything wired up, if we click on the create button we should be able to add the book to our list.

Angular1_04

Note: There is a small problem here that the invalid book entities will also go to the list. Even if we just hit Create without typing anything, an entry will be created. How to fix it, we will look a bit later in next section.

Editing an Entity

Now that we have all the edit functionality also ready in the controller and service, perhaps we should work on how to create an edit form. The first thing we need to do is to have an edit button for each book entity so that clicking on this will indicate which entity the user wants to update. We can do this by calling our $scope.setEditBook function. So lets do this in our ng-repeat block.

Angular1_05

Now whenever the user will click on this button the selected row’s entity will be set as the book that the user want to edit. Let us now create a form for edit. This form will be similar to the one we created for create in the sense that it should be bound to $scope.editBook and the submission should call the updateBookfunction. But we need to have a few extra things here. First thing we need to do is to keep track of the ID. Since we are working with the copy of actual model here, we will have the IDput in a hidden field on this form. Second thing we need to do is to have a cancel button which will reset the editBookobject and effectively resets the update request.

Angular1_06

Now when we run this application and select an item for edit we can see that it is being selected as the item for edit.

Angular1_07

Now if we update the ISBN value to 1234 and hit upate, we can see the changes getting effected in the list.

Angular1_08

Now we have the forms for create and update ready. The edt still doesn’t have any validations in place but we will look at the validation in next section.

Note: In the sample application, by default the create form is visible. The moment user selects an item to edit, the create form will go away and the edit form will become visible. We could have used same for for both create and edit but that is deliberately not being done to avoid complexity and keep the code free from digression.

Understanding Angular Validation Framework

The current implementation has the major problem that there are no validations in place. angular provides quite a few features that makes validation very easy. Also it works in unison with the HTML5 validation attributes so that is also a good thing. To illustrate how these validation works lets have a very simple validation rule that all the fields are required in our application. Lets see how we can implement this in our application.

The first thing that we need to do is to let the application know that we are taking control of validation in our hands and we dont want the default HTML5 validations. This can be done by setting the novalidateattribute on the form tag. Also to be able to use the validations, we need to have a name for the form. Angular uses this name to let us know the state of form controls.

Angular1_09

With this small change in place, we are ready to put our validations. First to implement the required validation lets put the requiredattribute for all our inputs.

Angular1_10

Now lets start looking at the magic angular does. Angular has few properties associated with all the input elements which are in the ng-form. Here are some of these properties.

  • $pristine
  • $dirty
  • $valid
  • $invalid

The $pristine will be true if the input value has not been changed since the page loaded. The $dirty is exactly opposite. It is true when the value has been changed. $valid is true if the input contains a valid value and the $invalidis exact opposite that it contains true then the input element contains invalid value.

Now how can we use these properties for validation. What we will do is that whenever the input contains invalid value, we will not let the user submit the form. We can do this by passing the form object in the addBooksfunction and check whether is it valid or not.

Angular1_11

Now this will prevent the invalid book entry from getting saved. But it would also be nice if we could have immediate feedback when we are editing the page. So lets try to apply some css class on individual elements using these properties. To be able to use these properties on individual elements, each input element must have a nameand it should be bound using ng-model. So lets try to do this for the book name.

Angular1_12

What we are doing here is that we are checking if the input field is dirtyi.e. the user has started changing the values and if its invalid, we attach a css class to the element. This css class is simple showing a red border if the input field is invalid and has been touched.

Angular1_13

So using these above shown properties we can perform validations in many different ways on our form. Perhaps one idea could be to disable the submit button itself if the form values are not valid. For individual properties also we could implement a lot of CSS based feedback mechanism using these properties.

Note: I have not implemented this CSS based feedback for all field. It has been done on only 1 field for demonstration purpose. The validation for add and edit have been done in the controller to avoid the invalid values in the list.

Point of interest

In this article we talked about the basics of angular data entry forms. We also looked at how to perform validations using angular provided properties on form input elements. All that we have seen is just the tip of the iceberg as there are a lot of best practices available when it comes to building data entry forms. We have also not looked at Angular UI which is another plugin that can be used to ease up the form creation using bootstrap components. The main intention of this article was to get the reader acquainted with the ngForm directive and how we can perform data entry and validation using angular. This has been written from a beginner’s perspective. I hope this has been informative.

Download the sample code from here: SampleApp6