Your First AngularJS App: Responding to User Interaction

You have seen how behaviors and directives can be combined to create app features, and it is this combination that drives much of the functionality in an AngularJS app. One of the most powerful combinations is achieved when using directives and behaviors to respond to user interaction. In Listing 2-9, you can see the additions I made to the todo.html file to allow the user to create new to-do items.

Listing 2-9. Responding to User Input 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;

}

$scope.warningLevel = function () {

return $scope.incompleteCount() < 3 ? “label-success” : “label-warning”;

}

$scope.addNewItem = function (actionText) {

$scope.todo.items.push({ action: actionText, done: false });

}

});

</script>

</head>

<body ng-controller=”ToDoCtrl”>

<div class=”page-header”>

<h1>

{{todo.user}}’s To Do List

<span class=”label label-default” ng-class=”warningLevel()”

ng-hide=”incompleteCount() == 0″>

{{incompleteCount()}}

</span>

</h1>

</div>

<div class=”panel”>

<div class=”input-group”>

<input class=”form-control” ng-model=”actionText” />

<span class=”input-group-btn”>

<button class=”btn btn-default”

ng-click=”addNewItem(actionText)”>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>

<td><input type=”checkbox” ng-model=”item.done” /></td>

</tr>

</tbody>

</table>

</div>

</body>

</html>

I have added a behavior called addNewItem that takes the text of a new to-do item and adds an object to the data model, using the text as the value for the action property and setting the done property to false, like this:

$scope.addNewItem = function(actionText) {

$scope.todo.items.push({ action: actionText, done: false});

}

This is the first behavior I have shown you that modifies the model, but in a real project there is usually a much more even split between behaviors that obtain and prepare data for the view and those that respond to user interaction and update the model. Notice that my behavior is still defined as a standard JavaScript function and that I am able to update the model using the push method that JavaScript supports for arrays.

The magic in this example comes in the use of directives, of which there are two. Here is the first of them:

<input class=”form-control” ng-model=”actionText” />

This is the same ng-model directive that I used when I set up the check boxes, and you’ll encounter this directive a lot when working with form elements. The point to note is that I have specified the name of a property for the directive to update that is not part of the model. The ng-model directive will dynamically create the property for me within the scope of the controller, effectively creating dynamic model properties that are used to handle user input.

I use the dynamic property in the second directive I added to the example:

<button class=”btn btn-default” ng-click=”addNewItem(actionText)”>Add</button>

The ng-click directive sets up a handler that evaluates the expression when the click event is triggered. In this case, the expression invokes the addNewItem behavior, passing the dynamic actionText property as the argument. This has the effect of adding a new to-do item that contains the text that the user entered into the input element, as shown in Figure 2-8.

Tip You have probably been drilled not to add event handling code to individual elements, so it may seem odd to apply the ng-click directive to the button element. Don’t worry—when AngularJS compiles the HTML file and encounters the directive, it sets up a handler following the unobtrusive JavaScript approach, such that the event handler code is separate from the element. It is important to differentiate between the AngularJS directives and the HTML and JavaScript that are generated from those directives during compilation.

Notice that the label that displays the number of incomplete to-do items updates automatically when you add a new item to the list. One of the benefits of the live model in AngularJS apps is that your bindings and behaviors create a foundation of features that work together.

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 *