<!DOCTYPE html> <html> <head> <script src="angular.js"></script> <script src="script.js"></script> <style> table { border-collapse: collapse; } table, th, td { border: 1px solid #e1e1e1; } th, td { padding: 6px; } thead { background-color: #fcfcfc; } </style> </head> <body ng-app="mainModule"> <div ng-controller="mainController"> <h3>1. Simple table</h3> <table> <thead> <tr> <th>First name</th> <th>Last name</th> </tr> </thead> <tbody> <tr ng-repeat="person in people"> <td>{{person.firstName}}</td> <td>{{person.lastName}}</td> </tr> </tbody> </table> <br /> <h3>2. Table with rows selection</h3> <table> <thead> <tr> <th> <input type="checkbox" ng-model="areAllPeopleSelected" ng-change="updatePeopleSelection(selectablePeople, areAllPeopleSelected)" /> </th> <th>First name</th> <th>Last name</th> </tr> </thead> <tbody> <tr ng-repeat="person in selectablePeople"> <td><input type="checkbox" ng-model="person.isSelected" /></td> <td>{{person.firstName}}</td> <td>{{person.lastName}}</td> </tr> </tbody> </table> <br /> <h3>3. List with special variables</h3> <ul> <li ng-repeat="person in people"> {{$index + 1}}. {{person.firstName}} {{person.lastName}} <strong>{{getPersonPositionDesc($first, $middle, $last, $even, $odd)}}</strong> </li> </ul> <br /> <h3>4. Nested lists with object's properties</h3> <ul> <li ng-repeat="person in selectablePeople"> <strong>Object {{$index + 1}}</strong> <ul> <li ng-repeat="(propName, propValue) in person"> {{$index + 1}}. <strong>name =</strong> {{propName}}, <strong>value =</strong> {{propValue}} </li> </ul> </li> </ul> <br /> <h3>5. Add and remove items</h3> <button ng-click="addStringToArray()">Add item</button><br /> <br /> <table> <tbody> <tr ng-repeat="str in stringsArray"> <td><button ng-click="$parent.removeStringFromArray($index)" />Remove</td> <td>{{str}}</td> </tr> </tbody> </table> </div> </body> </html>
angular.module("mainModule", []) .controller("mainController", function ($scope) { // Initialization $scope.areAllPeopleSelected = false; $scope.people = [ {firstName: "John", lastName: "Doe"}, {firstName: "Bob", lastName: "Smith"}, {firstName: "Jack", lastName: "White"}, {firstName: "Michael", lastName: "Green"} ]; $scope.selectablePeople = [ {firstName: "John", lastName: "Doe", isSelected: false}, {firstName: "Bob", lastName: "Smith", isSelected: false}, {firstName: "Jack", lastName: "White", isSelected: false}, {firstName: "Michael", lastName: "Green", isSelected: false} ]; $scope.stringsArray = []; var currStringIndex = 0; // Utility functions $scope.updatePeopleSelection = function (peopleArray, selectionValue) { for (var i = 0; i < peopleArray.length; i++) { peopleArray[i].isSelected = selectionValue; } }; $scope.getPersonPositionDesc = function(isFirst, isMiddle, isLast, isEven, isOdd) { var result = ""; if (isFirst) { result = "(first"; } else if (isMiddle) { result = "(middle"; } else if (isLast) { result = "(last"; } if (isEven) { result += "-even)"; } else if (isOdd) { result += "-odd)"; } return result; }; $scope.addStringToArray = function () { $scope.stringsArray.push("Item " + currStringIndex); currStringIndex++; }; $scope.removeStringFromArray = function (stringIndex) { if (stringIndex >= 0 && stringIndex < $scope.stringsArray.length) { $scope.stringsArray.splice(stringIndex, 1); } }; });



The ng-repeat directive allows us to iterate over a collection and create a DOM element (with the corresponding eventual subtree) for each item in the collection. Every time the collection changes, the DOM is updated as well. We can iterate over an array or over the properties of an object.

In point 1 of the example we iterate over a people array that we have initialized in the script file and added to the $scope of mainController. Each item in the array is an object with a firstName and a lastName property. For each iteration, the object is assigned to the person variable and a new tr element is created with the corresponding subtree (the td elements).

In point 2 we see how a change in the model is reflected in the DOM tree generated by the ng-repeat directive. We have a checkbox for each row that can be selected/deselected and is bound to the isSelected property of each item in the model array. We also have a checkbox in the table header that allows to select/deselect all the rows by setting the isSelected property of each row accordingly.

In point 3 we generate the items of a list and we also use some special variables that are populated by the ng-repeat directive. Here are the available special variables:

  • $index: the zero-based index of the current item in the collection
  • $first: true if the current item is the first one in the collection, false otherwise
  • $middle: true if the current item is in the middle of the collection (after the first one, but before the last), false otherwise
  • $last: true if the current item is the last one in the collection, false otherwise
  • $even: true if the current $index is even, false otherwise
  • $odd: true if the current $index is odd, false otherwise
Note that in the example we set the number in front of the list item by incrementing by 1 the $index, so the numbers start from one, but the $even and $odd variables consider the $index as is, so the first item is even ($index is 0), the second one is odd ($index is 1) and so on.

In point 4 we see how we can enumerate the properties of an object. We have two nested ng-repeat directives. The first one iterates over the array items, while the second one iterates over the properties of each item getting their name and value. As you can see, the properties are sorted in alphabetical order and this behavior cannot be changed. An interesting test you can do in the example, is observe how the values of the isSelected properties in this list change whenever you select/deselect a row in point 2 because both the points of the example are using the same selectablePeople array.

In point 5 we can try to dynamically add and remove items from an array and see that the collection rendering is updated accordingly whenever the monitored model array changes. Here you can see that we must use the $parent scope for the remove button because the ng-repeat directive creates a new scope for each tr it creates and the removeStringFromArray function is defined on the $scope of mainController.

The ng-repeat directive creates a new scope for each DOM subtree that it creates.