AngularJS でコントローラーをネストする

AngularJS ではコントローラーを入れ子にして、ng-repeat で処理するコレクションの要素1つ1つに子コントローラーをバインドすることができる。

例えば、よく見かける ToDo アプリのサンプルだとこんな感じ。

<!DOCTYPE html>
<html ng-app>
  <head>
    <meta charset="utf-8">
    <title>Angular Sample</title>
    <style type="text/css">
      .done-true {
        text-decoration: line-through;
        color: grey;
      }
    </style>
    <script type="text/javascript" src="angular.js"></script>
    <script type="text/javascript">
      function MainCtrl($scope) {
        $scope.newTodo = "";
        $scope.todos = [];

        $scope.addTodo = function() {
          $scope.todos.push({
            name: $scope.newTodo,
            completed: false
          });
          $scope.newTodo = "";
        };
      };

      function TodoCtrl($scope, $window) {
        $scope.destroy = function() {
          if (!$window.confirm($scope.todo.name + "を削除していいですか?")){
            return;
          }

          // 親(MainCtrl) の todos にアクセスできる
          for (var i = 0, len = $scope.todos.length; i < len; i++) {
            if ($scope.todos[i] === $scope.todo) {
              $scope.todos.splice(i, 1);
              break;
            }
          }
        };
      };
    </script>
  </head>
  <body ng-controller="MainCtrl">
    <input type="text" ng-model="newTodo" placeholder="Input Todo"/>
    <button ng-click="addTodo()">Add</button>
    <table>
      <tr ng-repeat="todo in todos" ng-controller="TodoCtrl">
        <td><input type="checkbox" ng-model="todo.completed"/></td>
        <td><span class="done-{{todo.completed}}">{{ todo.name }}</span></td>
        <td><a href="#" ng-click="destroy()">[x]</a></td>
      </tr>
    </table>
  </body>
</html>

子コントローラーにバインドされた、コレクションの各要素には $scoep からアクセスできるし、親コントローラーの $scope で格納したデータにもアクセスできる。