Working with Forms with AngularJS: Using the Form Directive Attributes

As I explained earlier in this chapter, AngularJS provides its form features using directives that replace the standard form elements, such as form, input, and select. These directives support optional attributes that can be used to integrate form elements more closely into the AngularJS style of application development. In the sections that follow, I detail each of the form elements for which there are AngularJS replacement directives and describe the additional attributes you can use to fine-tune the way forms work.

1. Using Input Elements

The directive that AngularJS uses for input elements provides some additional attributes that can be used to improve integration with the data model, as described in Table 12-5. 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.

Some of these attributes are described elsewhere, but in Listing 12-12 you can see how the others are applied to perform validation.

Listing 12-12. Using the Attributes for input Elements 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.requireValue = true;

$scope.matchPattern = new RegExp(“^[a-z]”);

});

</script>

</head>

<body>

<div id=”todoPanel” class=”panel” ng-controller=”defaultCtrl”>

<form name=”myForm” novalidate>

<div class=”well”>

<div class=”form-group”>

<label>Text:</label>

<input name=”sample” class=”form-control” ng-model=”inputValue”

ng-required=”requireValue” ng-minlength=”3″

ng-maxlength=”10″ ng-pattern=”matchPattern”>

</div>

</div>

<div class=”well”>

<p>Required Error: {{myForm.sample.$error.required}}</p>

<p>Min Length Error: {{myForm.sample.$error.minlength}}</p>

<p>Max Length Error: {{myForm.sample.$error.maxlength}}</p>

<p>Pattern Error: {{myForm.sample.$error.pattern}}</p>

<p>Element Valid: {{myForm.sample.$valid}}</p>

</div>

</form>

</div>

</body>

</html>

I have used the ng-required, ng-minlength, ng-maxlength, and ng-pattern attributes, all of which apply validation constraints. The effect is that I have created an element that is valid only if the user has supplied a value and that value starts with a lowercase letter and is between three and ten characters long. I have added a set of data bindings that display the validation status for the individual constraints and the input element overall, as shown in Figure 12-10.

Note When the type attribute is email, url, or number, AngularJS sets the ng-pattern automatically to check the formatting. You should not set the ng-pattern attribute on these types of input element.

1.1. Using Checkboxes

Table 12-6 shows the additional attributes that are available when you use an input element whose type attribute is set to checkbox.

You can see a simple example of using the ng-true-value and ng-false-value attributes in Listing 12-13.

Listing 12-13. Using the Additional Attributes for Check Boxes 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) {});

</script>

</head>

<body>

<div id=”todoPanel” class=”panel” ng-controller=”defaultCtrl”>

<form name=”myForm” novalidate>

<div class=”well”>

<div class=”checkbox”>

<label>

<input name=”sample” type=”checkbox” ng-model=”inputValue”

ng-true-value=”Hurrah!” ng-false-value=”Boo!”>

This is a checkbox

</label>

</div>

</div>

<div class=”well”>

<p>Model Value: {{inputValue}}</p>

</div>

</form>

</div>

</body>

</html>

The values of the ng-true-value and ng-false-value attributes will be used to set the model binding expression, but only when the state of the check box changes. This means that the model property—if implicitly defined—will not be created until the user interacts with the element. See the “Implicitly Creating Model Properties” section earlier in this chapter for further details.

2. Using Text Areas

AngularJS includes a directive for the textarea element, which supports the same attributes as described in Table 12-5. You can see a simple example of applying some of these attributes in Listing 12-14. This is the same basic example I used in Listing 12-12 but with a textarea instead of an input element.

Listing 12-14. Using the Additional Attributes for the textarea Element 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.requireValue = true;

$scope.matchPattern = new RegExp(“^[a-z]”);

});

</script>

</head>

<body>

<div id=”todoPanel” class=”panel” ng-controller=”defaultCtrl”> form name=”myForm” novalidate>

<div class=”well”>

<div class=”form-group”>

<textarea name=”sample” cols=”40″ rows=”3″

ng-model=”textValue”

ng-required=”requireValue” ng-minlength=”3″

ng-maxlength=”10″ ng-pattern=”matchPattern”>

</textarea>

</div>

</div>

<div class=”well”>

<p>Required Error: {{myForm.sample.$error.required}}</p>

<p>Min Length Error: {{myForm.sample.$error.minlength}}</p>

<p>Max Length Error: {{myForm.sample.$error.maxlength}}</p>

<p>Pattern Error: {{myForm.sample.$error.pattern}}</p>

<p>Element Valid: {{myForm.sample.$valid}}</p>

</div>

</form>

</div>

</body>

</html>

3. Using Select Elements

The directive that AngularJS uses for select elements defined the ng-required attribute that is available for input elements and an ng-options attribute that can be used to generate option elements from arrays and objects. Listing 12-15 provides an example of using the ng-options attribute.

Listing 12-15. Using the ng-options Attribute on a select Element 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.todos = [

{ id: 100, action: “Get groceries”, complete: false },

{ id: 200, action: “Call plumber”, complete: false },

{ id: 300, action: “Buy running shoes”, complete: true }];

});

</script>

</head>

<body>

<div id=”todoPanel” class=”panel” ng-controller=”defaultCtrl”>

<form name=”myForm” novalidate>

<div class=”well”>

<div class=”form-group”>

<label>Select an Action:</label>

<select ng-model=”selectValue”

ng-options=”item.action for item in todos”>

</select>

</div>

</div>

<div class=”well”>

<p>Selected: {{selectValue || ‘None’}}</p>

</div>

</form>

</div>

</body>

</html>

For this example, I have defined a data model that contains three to-do items and, in addition to the action and complete properties that I have been using in earlier example, I have defined an id attribute.

For the select element, I have set the ng-options attribute so that option elements are generated for each of the to-do items, as follows:

<select ng-model=”selectValue” ng-options=”item.action for item in todos“>

This is the basic ng-options expression, and it is in the format <label> for <variable> in <array>. AngularJS will generate an option element for each object in the array and set the contents to be the label. For this listing, the select element generates the following HTML:

<select ng-model=”selectValue” ng-options=”item.action for item in todos”

class=”ng-pristine ng-valid”>

<option value=”?” selected=”selected”></option>

<option value=”0″>Get groceries</option>

<option value=”1″>Call plumber</option>

<option value=”2″>Buy running shoes</option>

</select>

Using the ng-options attribute is similar to using the ng-repeat directive, but with some additions and quirks that are particular to select elements.

3.1. Changing the First Option Element

Notice that the output from the select element contains an option element whose value attribute is a question mark and that has no content. AngularJS generates this when the property specified by the ng-model attribute is undefined. I can replace this default option element by adding my own with an empty value attribute, as shown in Listing 12-16.

Listing 12-16. Replacing the Default Option Element in the forms.html File

<select ng-model=”selectValue” ng-options=”item.action for item in todos”>

<option value=””>(Pick One)</option>

</select>

This produces the following HTML:

<select ng-model=”selectValue” ng-options=”item.action for item in todos”

class=”ng-pristine ng-valid”>

<option value=”” class=””>(Pick One)</option>

<option value=”0″>Get groceries</option>

<option value=”1″>Call plumber</option>

<option value=”2″>Buy running shoes</option>

</select>

3.2. Changing the Selection Value

By default, picking an option element in a select element causes the ng-model expression to be updated with the object in the collection. You can see this by loading forms.html in the browser and making a selection. There is a data binding at the bottom of the page that shows the selectValue model property, which is implicitly defined by the select element, as Figure 12-11 illustrates.

You won’t always want to use the complete source object to set the ng-model value; you can use a slightly different expression for the ng-options attribute to specify one of the properties from the object, as shown in Listing 12-17.

Listing 12-17. Specifying a Property as the ng-model Value in the forms.html File

<select ng-model=”selectValue”

ng-options=”item.id as item.action for item in todos”>

<option value=””>(Pick One)</option>

</select>

The expression is in the form <selected property> as <label> for <variable> in <array>, and in the listing, I have specified that the item.id is the value I want used when the user picks an option element. You can see the effect of this change in Figure 12-12.

3.3. Creating optgroup Elements

The ng-options attribute can be used to group items together based on the value of a property, generating a set of optgroup elements for each value that is encountered. Listing 12-18 provides an example, in which I have added a place property to the to-do object in the model.

Listing 12-18. Generating optgroup Elements 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.todos = [

 { id: 100, place: “Store”, action: “Get groceries”, complete: false },

{ id: 200, place: “Home”, action: “Call plumber”, complete: false },

{ id: 300, place: “Store”, action: “Buy running shoes”, complete: true }];

});

</script>

</head>

<body>

<div id=”todoPanel” class=”panel” ng-controller=”defaultCtrl”>

<form name=”myForm” novalidate>

<div class=”well”>

<div class=”form-group”>

<label>Select an Action:</label>

<select ng-model=”selectValue”

ng-options=”item.action group by item.place for item in todos”>

<option value=””>(Pick One)</option>

</select>

</div>

</div>

<div class=”well”>

<p>Selected: {{selectValue || ‘None’}}</p>

</div>

</form>

</div>

</body>

</html>

The property that is used to group objects together is specified with group by in the ng-options expression. In this example, I have specified that the place property should be used to group elements, which causes the following HTML to be generated:

<select ng-model=”selectValue”

ng-options=”item.action group by item.place for item in todos”

class=”ng-pristine ng-valid”>

<option value=”” class=””>(Pick One)</option>

<optgroup label=”Store”>

<option value=”0″>Get groceries</option>

<option value=”2″>Buy running shoes</option>

</optgroup>

<optgroup label=”Home”>

<option value=”1″>Call plumber</option>

</optgroup>

</select>

You can see how the browser uses the optgroup element to add structure to the select element menu in Figure 12-13.

Tip You can combine the selection value and grouping features by using an expression such as item.id as item.action group by item.place for item in todos.

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 *