AngularJS テンプレートとデータバインディング

2.3.10（p34）までの内容。本書の内容を丸写ししているわけでなく、いくつかのコードを一纏めにしたりアレンジを加えたりしている。そのため少し見えづらいところも。

一般的なAngularJSの構造。

```index.html
<html ng-app="myApp"> <!-- 名前を付けるのを忘れずに -->
  <body ng-controller="TextController">
    <p>{{someText.message}}</p> <!-- view1 -->
    <p ng-bind="someText.message"></p> <!-- view2 こちらでも表示可能 -->

    <!--
      [view 1の問題]
        angluar.jsが読み込まれるまで "{{someText.message}}" という文字列が表示されることになる
    -->

    <!-- CDN(コンテンツ配信ネットワーク)経由 -->
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js">
    </script>
    <!--
      [CDNのメリット]
        1. 高速なGoogleのサーバから読み込める
        2. アプリケーション間にまたがってスクリプトをキャッシュできる
         -> angularを扱うアプリが複数あったとしても, 同じURIから取得するから読み込みは1度のみ
    -->

    <script>
      // moduleの定義. 第二引数は何だろう?
      var myAppModule = angular.module("myApp", []);

      // moduleにcontrollerを定義
      // グローバル変数の汚染を防ぐメリットがある
      myAppModule.controller("TextController", function($scope) { // controller
        var someText = {}; // model
        someText.message = "旅の始まりです";
        $scope.someText = someText;
      });
    </script>
  </body>
</html>
```
<hr>

テンプレート、データバインディング。属性"ng-xxxxx"でイベントを付与したり、valueやclassを変更したりできる。

```index2.html
<html ng-app="myApp">
  <body>
    <form ng-controller="StartUpController">
      <!-- 見込み1: <input ng-change="computeNeeded()" ng-model="funding.startingEstimate"><br>
      -->
      見込み2: <input ng-model="funding.startingEstimate"><br>
      推奨額: <span ng-bind="funding.needed"></span><br>
      <!-- クリック, ダブルクリックに対応するディレクティブ -->
      <button ng-click="requestFunding()">出資を依頼する！</button><br>
      <button ng-dblclick="reset()">リセット</button><br>
    </form>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js">
    </script>

    <script>
      var myAppModule = angular.module("myApp", []);

      myAppModule.controller("StartUpController", function($scope) {
        $scope.funding = { startingEstimate : 0 };

        // 見込み1の場合
        // <input>の中身が変わった時に'のみ', 以下のfunction()が実行
        // $scope.computeNeeded = function() {
        //   $scope.funding.needed = $scope.funding.startingEstimate * 10;
        // };

        // 見込み2の場合
        // $scope.$watchでfunction.startingEstimateを監視対象へ
        // funding.startingEstimateが変更する度に, computeNeeded()が走る
        var computeNeeded =  function() {
          $scope.funding.needed = $scope.funding.startingEstimate * 10;
        };
        $scope.$watch("funding.startingEstimate", computeNeeded);

        $scope.requestFunding = function() {
          alert("もっと顧客を増やしてからにしてください");
        };

        // 見込み1の場合は, 推奨額はゼロにならないことに注意
        $scope.reset = function() {
          $scope.funding.startingEstimate = 0;
        };
      });

    </script>
  </body>
</html>
```
見込みに数字を入れると自動的に推奨額が算出される。ボタンの動作はコードを見れば明らか。
![スクリーンショット 2014-06-22 21.16.02.png](https://qiita-image-store.s3.amazonaws.com/0/46596/4bec8ff5-9e8d-a9f0-27fd-e96b1212a419.png)

<hr>

```index3.html
<html ng-app="myApp">
  <style>
  <!--
    .before_add {
      color : #aaaaff;
    }
    .after_add {
      color : #ffaaaa;
    }
  -->
  </style>

  <body>

    <div ng-controller="StudentListController">
      <ul ng-show="listState.show">
        <!-- 繰り返し -->
        <li ng-repeat="student in students">
          <!-- $index は0スタート -->
          {{$index + 1}} : <a href="/student/view/{{student.id}}">{{student.name}}</a>,
          <!-- 動的クラス変更 (ng-classではなく, classのままだと動的にならない) -->
          <span ng-class="{ before_add : !isAdd, after_add : isAdd }">
            <!-- $first, $middle, $last は真偽値($middleはリストの最初と最後以外でtrue -->
            first : {{$first}},
            middle : {{$middle}},
            last : {{$last}}
          </span>
        </li>
        <button ng-click="insertTom()">追加</button>
      </ul>
      <button ng-click="toggleList()">リストをトグル</button>

    <!--
       [補足]
       src, hrefを動的に変更するには, classのときと同様にそれぞれng-src, ng-hrefを使用する.
         <img ng-src="/xxx/yyy/id={{hoge_id}}">
         <a ng-href="/xxx/yyy/id={{hoge_id}}">リンク</a>
    -->

    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js">
    </script>

    <script>
      var students = [
        { name : "メアリー", id : 1 },
        { name : "ジャック", id : 101 },
        { name : "マイケル", id : 55 }
      ]

      var myAppModule = angular.module("myApp", []);

      myAppModule.controller("StudentListController", function($scope) {
        $scope.students = students;
        $scope.insertTom = function() {
          $scope.students.splice(1, 0, { name : "トム", id : 492 });
          $scope.isAdd = true;
        };

        $scope.listState = { show : false };
        $scope.toggleList = function() {
          $scope.listState.show = !$scope.listState.show;
        };

      });

    </script>
  </body>
</html>
```

最初は listState.show が false のために ul は非表示。
![スクリーンショット 2014-06-22 21.19.01.png](https://qiita-image-store.s3.amazonaws.com/0/46596/506fb44c-8e94-a891-34d9-24b3d9f4e006.png)

表示。
![スクリーンショット 2014-06-22 21.21.18.png](https://qiita-image-store.s3.amazonaws.com/0/46596/6a8451d5-883c-aa2c-c213-da999fe3defe.png)
`<span ng-class="{ before_add : !isAdd, after_add : isAdd }">`が効いていて first, middle, lastに css が適用されている。また、それぞれのリンク先は`<a href="/student/view/{{student.id}}">`で指定した通り、モデルのidになっている。

追加を押すとトム追加。
![スクリーンショット 2014-06-22 21.24.35.png](https://qiita-image-store.s3.amazonaws.com/0/46596/a5214d75-aec5-299b-1639-61fb19bbefc0.png)
isAdd = true により class が after_add へ。適用される css が変化。
特に制御しているわけではないので、ボタンを押す度にトムが追加される。
JavaScriptのメソッドsplice()で配列を操作すれば、生徒を追加したり削除したりできる。

どうしてこのような書き方をするのか？
↓
Unobtrusive JavaScript（控えめなJavaScript）
・HTMLとJavaScriptの分離
・JavaScriptのコード散乱を防ぐ。そのためのMVC。