Working with Forms with AngularJS: Validating Forms

The change I made in the previous section prevents a JavaScript error, but it has the effect of allowing the user to interact with the application without producing a result or an error. I have fixed one problem, the JavaScript error, and introduced another: a confused user.

I wanted to show you the need to check for the existence of the data obj ect because it is a common problem, but the underlying issue is that my simple example app has a constraint, which is that I need to receive an action and a location from the user before creating a new to-do item. I have enforced this constraint in my code, but I really need to tell the user about it as well—and that leads neatly into the world ofform validation.

Most web applications need to receive data from the user. Users dislike forms, especially on touch-enabled devices, and even the best-intentioned users will enter unexpected data. There are some good reasons for this—see the “Are My Users Stupid?” sidebar for a summary—but the result is that you will need to check the data that users provide before using it. AngularJS provides comprehensive support for validating form data, which I describe in the sections that follow.

1. Performing Basic Form Validation

AngularJS provides basic form validation by honoring the standard HTML element attributes, such as type and required, and adding some directives. In Listing 12-5, I have simplified the forms.html file to focus on the form elements in order to demonstrate the basic validation support.

Listing 12-5. Performing Basic Form Validation in the forms.html File

<!DOCTYPE html>

<html ng-app=”exampleApp”>

<head>

<title>Forms</title>

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

<link href=”bootstrap.css” rel=”stylesheet” />

<link href=”bootstrap-theme.css” rel=”stylesheet” />

<script>

angular.module(“exampleApp”, [])

.controller(“defaultCtrl”, function ($scope) {

$scope.addUser = function (userDetails) {

$scope.message = userDetails.name

+ ” (” + userDetails.email + “) (” + userDetails.agreed + “)”;

}

$scope.message = “Ready”;

});

</script>

</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: {{myForm.$valid}}

</div>

</div>

</form>

</div>

</body>

</html>

There is a lot going on in this example, and the best place to start is by showing you the overall effect before digging into the detail. In Figure 12-4, I have shown the initial state of the HTML document when it is loaded by the browser. There are three input elements and an OK button that is disabled and cannot be clicked.

Figure 12-4 also shows you what happens if you enter values into the input elements and check the box: The button is enabled, allowing the user to submit the form. In the sections that follow, I’ll show you how I arranged this behavior and, in doing so, describe the most basic AngularJS form validation features.

Tip In addition to the built-in form validation features that I describe in this chapter, AngularJS supports validation through custom directives, which I explain in Chapter 17.

1.1. Adding the Form Element

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

Tip 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, which I describe in the “Using the Form Directive Attributes” section later in this chapter.

When AngularJS encounters a form element, it automatically sets up the basic features I describe in this chapter and processes the child elements to look for other elements it needs to process, such as the input element. With this in mind, here is the form element from the example:

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

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 (I describe these variables shortly).

Tip You don’t have to add a form element to a document if you want to use features like two-way model binding; it is just form validation that requires a form element.

As I’ll demonstrate in the next section, AngularJS uses standard HTML attributes to configure form validation. This is a problem because the latest versions of the mainstream browsers also use those attributes, but they do it inconsistently and for a smaller range of element types (and some browsers, notably those on mobile devices, just ignore them). To disable the browser validation support and enable the AngularJS features, I have added the novalidate attribute to my 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 element is the ng-submit directive, which I described in Chapter 11. As a reminder, this directive specifies a custom response to a submit event, which is triggered when the user submits the form (in this example by clicking the OK button). In this example, I have specified that the addUser controller behavior is invoked, passing in an implicitly defined object called newUser, which I create through the ng-model directive applied to individual elements within the form.

1.2. Using Validation Attributes

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 (and which I describe later in this chapter).

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 (denoting an e-mail address). HTML5 defines a new set of type attribute values for input elements, and the ones that AngularJS can validate are described in Table 12-2.

In addition to the formats specified by the type attribute, I can apply further constraints through a mix of standard attributes and AngularJS directives. In the example, I have used the required attribute, which specifies that the user must provide a value for the form to be valid. When this is combined with the type attribute value, the effect is to tell AngularJS that the user must provide a value and that value must be formatted as an e-mail address.

There are different attributes for each type of input element, and AngularJS defines a set of optional directives for each element type that can be used to customize the validation. I describe each element and the attributes and directives available later in this chapter.

For the other input elements in the example, I have specified only the required attribute. For the text type input element, this just means that the user is required to enter a value but without any specific format validation:

<input name=”userName” type=”text” class=”form-control” required ng-model=”newlser.name”>

I have specified the type attribute for this input element, but omitting it has the same effect as setting it to text, as I have done here. The final input element in this example is a check box:

<input name=”agreed” type=”checkbox” ng-model=”newlser.agreed” required>

Each of the input elements uses the ng-model directive to set a property on the implicitly defined newlser object, and since all of the elements have the required attribute, the result is that the form will be valid only when the user has entered a name and a well-formatted e-mail address and checked the box.

1.3. 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. Table 12-3 describes the variables that are available.

As I’ll demonstrate later in this chapter, these variables can be used in combination to present the user with feedback about validation errors. For my current example, I used two of the special variables. The first use is through an inline data binding, like this:

<div>Valid: {{myForm.$valid}}</div>

This expression displays the $valid variable to represent the overall validity of the form element. I explained earlier in the chapter that it is important to use the name attribute on the elements that you want to validate, and this is why: AngularJS exposes the properties in the table via an object with the name value for each element, in this case myForm. The second variable I used was $invalid, and I used it in combination with another AngularJS directive, as follows:

<button type=”submit” class=”btn btn-primary btn-block” ng-disabled=”myForm.$invalid”>

OK

</button>

The $invalid property will return true if any of the elements in the form are not valid, and using this value as the expression for the ng-disabled directive ensures that the OK button is disabled until the form is valid.

Source: Freeman Adam (2014), Pro AngularJS (Expert’s Voice in Web Development), Apress; 1st ed. edition.

Leave a Reply

Your email address will not be published. Required fields are marked *