Controllers define behaviors on the scope. Behaviors are functions that operate on the data in the model to implement the business logic in the application. The behaviors defined by a controller support a view to display data to the user and to update the model based on user interactions.
To demonstrate a simple behavior, I am going to change the label displayed to the right of the header in todo.html so that it displays only the number of incomplete to-do items. You can see the changes required to do this in Listing 2-7. (I also removed the column that contains the true and false values, which I required only to demonstrate that data bindings reflected changes in the data model.)
Listing 2-7. Defining and Using a Controller Behavior in the todo.html File
<!DOCTYPE html>
<html ng-app=”todoApp”>
<head>
<title>TO DO List</title>
<link href=”bootstrap.css” rel=”stylesheet” />
<link href=”bootstrap-theme.css” rel=”stylesheet” />
<script src=”angular.js”></script>
<script>
var model = {
user: “Adam”,
items: [{ action: “Buy Flowers”, done: false },
{ action: “Get Shoes”, done: false },
{ action: “Collect Tickets”, done: true },
{ action: “Call Joe”, done: false }]
};
var todoApp = angular.module(“todoApp”, []);
todoApp.controller(“ToDoCtrl”, function ($scope) {
$scope.todo = model;
$scope.incompleteCount = function () {
var count = 0;
angular.forEach($scope.todo.items, function (item) {
if (!item.done) { count++ }
});
return count;
}
});
</script>
</head>
<body ng-controller=”ToDoCtrl”>
<div class=”page-header”>
<h1>
{{todo.user}}’s To Do List
<span class=”label label-default” ng-hide=”incompleteCount() == 0″>
{{incompleteCount()}}
</span>
</h1>
</div>
<div class=”panel”>
<div class=”input-group”>
<input class=”form-control” />
<span class=”input-group-btn”>
<button class=”btn btn-default”>Add</button>
</span>
</div>
<table class=”table table-striped”>
<thead>
<tr>
<th>Description</th>
<th>Done</th>
</tr>
</thead>
<tbody>
<tr ng-repeat=”item in todo.items”>
<td>{{item.action}}</td>
<tdxinput type=”checkbox” ng-model=”item.done” /></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Behaviors are defined by adding functions to the $scope object that is passed to the controller function. In the listing, I have defined a function that returns the number of incomplete items, which I determine by enumerating the objects in the $scope.todo.items array and counting the ones whose done property is false.
■ Tip I used the angular.forEach method to enumerate the contents of the data array. AngularJS includes some useful utility methods that supplement the JavaScript language. I describe the utility methods in Chapter 5.
The name of the property used to attach the function to the $scope object is used as the behavior name. My behavior is called incompleteCount, and I can invoke it within the scope of the ng-controller attribute, which applies the controller to the HTML elements that form the view.
I have used the incompleteCount behavior twice in Listing 2-7. The first is as a simple data binding to display the number of items, as follows:
…
<span class=”label label-default” ng-hide=”incompleteCount() == 0″>
{{incompleteCount()}}
</span>
…
Notice that I call the behavior using parentheses. You can pass objects as arguments to behaviors, which makes it possible to create general-purpose behaviors that can be used with different data objects. My application is sufficiently simple that I decided not to pass any arguments and instead get the data I require directly from the $scope object in the controller.
I also used the behavior in conjunction with a directive, like this:
…
<span class=”label default” ng-hide=”incompleteCount() == 0“>
{{incompleteCount()}}
</span>
…
The ng-hide directive will hide the element it is applied to—and its content elements—if the expression that is assigned as the attribute value evaluates to true. In this case, I call the incompleteCount behavior and check to see whether the number of incomplete items is zero; if it is, then the label that displays the number of items on the list is hidden from the user.
■ Tip The ng-hide directive is only one of a broad set of directives that manipulate the browser Document Object Model (DOM) automatically based on the state of the AngularJS model. I get into the detail of these directives in Chapter 11 and show you how to create your own directives in Chapters 15-17.
You can see the effect of the behavior and its application by using the browser to navigate to the todo.html file, as shown in Figure 2-6. Checking and unchecking items on the list changes the number of items displayed by the counter label, and checking all of the items causes the counter to be hidden.
Source: Freeman Adam (2014), Pro AngularJS (Expert’s Voice in Web Development), Apress; 1st ed. edition.