Web先端味見部 第5回(AngularJS) に行ってきた

Web先端味見部 第5回 に行ってきた。今回のテーマはvert.xの予定だったけど、予定を変更して、AngularJSになった。

AngularJSの概要については、以下のエントリが参考になる。


僕はJavaScriptMVCフレームワークを全く使ったことがない。Backbone.jsの名前はかろうじて知っているけど、さわったことはなかった。そんなわけで、AngularJSがはじめてのJS MVCフレームワークだった。

MVCだから、画面遷移をコントローラでいい感じに制御できて、いろんなデータをいい感じに画面にもってこれるのかなーとか考えていたけど、けっこう違った。
SpringMVC(使ったこと無いけど)というか、SAStratusというか、MVC対応のテンプレートエンジンとDIコンテナがセットになったなにか、という感じだった。


まずは簡単なサンプルをやってみた。ここで簡単に試せる。動かしてみると、けっこう感動した。

<!doctype html>
<html ng-app>
  <head>
    <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
  </head>
  <body>
    <div>
      <label>Name:</label>
      <input type="text" ng-model="yourName" placeholder="Enter a name here">
      <hr>
      <h1>Hello {{yourName}}!</h1>
    </div>
  </body>
</html>

angular-1.0.1.min.jsを読み込んで、ng-appってつけると、AngularJSが有効になる。あと ng-model="yourName"って付けたテキストボックスに文字を入れると、勝手に {{yourName}} って付けたところに入る。
こんな感じに yourAge を追加しても、いい感じに動く。

<!doctype html>
<html ng-app>
  <head>
    <script src="http://code.angularjs.org/angular-1.0.0.min.js"></script>
  </head>
  <body>
    <div>
      <label>Name:</label>
      <input type="text" ng-model="yourName" placeholder="Enter a name here">
      <label>age:</label>
      <input type="number" ng-model="yourAge" placeholder="Enter a name here">
      <hr>
      <h1>Hello {{yourName}}!</h1>
      <h1>Hello {{yourAge}}!</h1>
    </div>
  </body>
</html>


でも、ここから先は急に難しくなった。僕には。次のサンプルはtodoアプリ。

HTMLとJSはこんな感じだった。

<!doctype html>
<html ng-app>
  <head>
    <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
    <script src="todo.js"></script>
    <link rel="stylesheet" href="todo.css">
  </head>
  <body>
    <h2>Todo</h2>
    <div ng-controller="TodoCtrl">
      <span>{{remaining()}} of {{todos.length}} remaining</span>
      [ <a href="" ng-click="archive()">archive</a> ]
      <ul class="unstyled">
        <li ng-repeat="todo in todos">
          <input type="checkbox" ng-model="todo.done">
          <span class="done-{{todo.done}}">{{todo.text}}</span>
        </li>
      </ul>
      <form ng-submit="addTodo()">
        <input type="text" ng-model="todoText"  size="30"
               placeholder="add new todo here">
        <input class="btn-primary" type="submit" value="add">
      </form>
    </div>
  </body>
</html>
function TodoCtrl($scope) {
  $scope.todos = [
    {text:'learn angular', done:true},
    {text:'build an angular app', done:false}];
 
  $scope.addTodo = function() {
    $scope.todos.push({text:$scope.todoText, done:false});
    $scope.todoText = '';
  };
 
  $scope.remaining = function() {
    var count = 0;
    angular.forEach($scope.todos, function(todo) {
      count += todo.done ? 0 : 1;
    });
    return count;
  };
 
  $scope.archive = function() {
    var oldTodos = $scope.todos;
    $scope.todos = [];
    angular.forEach(oldTodos, function(todo) {
      if (!todo.done) $scope.todos.push(todo);
    });
  };
}

ポイントは <div ng-controller="TodoCtrl">function TodoCtrl($scope) { の2行。
TodoCtrl という名前の対応でJSが動くみたい。そして引数の $scope はAngularJSがインジェクションしてくれる。
$から始まる特定の名前のオブジェクトは Service と呼ばれていて、AngularJS が渡してくれる。Dependency Injection. このへんに書いてある。


例えばAjaxなどの機能は $http で定義されている。

これを使う場合は function TodoCtrl($scope, $http) { とすると、TodoCtrl で $http が使えるようになる。


僕が作ったサンプルはこんな感じ。Google Web Fontsのフォント名の一覧をJSONPで取ってきて、それを表示するだけ。
相変わらずポイントは <div ng-controller="FetchCtrl">function FetchCtrl($scope,$http) {

<!doctype html>
<html ng-app>
<head>
  <script src="http://code.angularjs.org/angular-1.0.0.min.js"></script>
  <script type="text/javascript">
  function FetchCtrl($scope,$http) {
    var url = 'https://www.googleapis.com/webfonts/v1/webfonts?key=AIzaSyAW8eNXU_2rMxcstFUzwjw85fK-uJ2rRqk&callback=JSON_CALLBACK';

    $scope.fetch = function() {
      $http.jsonp(url).success(function(data, status, headers, config) {
        $scope.fonts = data.items;
        console.log(data);
      }).
      error(function(data, status, headers, config) {
        alert(status);
      });
    }
  }
  </script>
</head>
<body>
  <div ng-controller="FetchCtrl">
    <button ng-click="fetch()">fetch</button><br>
    <ul class="unstyled">
      <li ng-repeat="font in fonts">
        <span class="done-{{todo.done}}">{{font.family}}</span>
      </li>
    </ul>
  </div>
</body>
</html>

JSONPの部分は jQuery で書くのとあまり変わらないけど、リストを生成するこの部分は、けっこう楽になると思う。いちいち新し要素をDOMに追加するコードを書かなくていい。ループは font in fontsで foreach っぽく書ける。

      <li ng-repeat="font in fonts">
        <span class="done-{{todo.done}}">{{font.family}}</span>
      </li>

これは楽でいいねー。

まとめ

冒頭に書いたけど、もう一度。MVC対応のテンプレートエンジンとDIコンテナがセットになったなにか、という感じだった。あとデータバインディングっぽいところは、かなり強力だった。
JavaScriptMVCっぽいことしたいというのは、やっぱり規模が大きくなっても見通しよく開発したいということだと思う。だから小規模なプロジェクトで AngularJS を始めとしたMVCフレームワークを使うと、習得コストが高くて元が取れないかも。
ただテンプレートエンジンっぽいところはお手軽に利用できるので、小規模ならここを中心に使うといいかも。


この勉強会、味見部はこんなことを目的に開催されている。

この「Web先端技術味見部」では、そうした 真新しい技術を実際に触ってみる ことを目的とした勉強会です。

新しい技術を1人で勉強するのは大変なので、こうやって他のひとの話を聞きながらいろいろ試せるのはすごくいい。
次回はこんな内容で、また参加するつもり。もうかなりキャンセル待ちだけど、ustもあるしみんなで新技術を触りましょ。