6
6

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-06-22

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>


テンプレート、データバインディング。属性"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


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

表示。
スクリーンショット 2014-06-22 21.21.18.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
isAdd = true により class が after_add へ。適用される css が変化。
特に制御しているわけではないので、ボタンを押す度にトムが追加される。
JavaScriptのメソッドsplice()で配列を操作すれば、生徒を追加したり削除したりできる。

どうしてこのような書き方をするのか?

Unobtrusive JavaScript(控えめなJavaScript)
・HTMLとJavaScriptの分離
・JavaScriptのコード散乱を防ぐ。そのためのMVC。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6