AngularJSを使ってみた
AngularJSを使って記事を書いていたら、事情により下記途中の記事が吹っ飛んでしまった・・・。再度書きなおしを行うこととなり、間がかなり空いてしまった。
AngularJSはHTMLをテンプレートとして扱う動的Webアプリケーションを作るためのフレームワークである。特にCRUDアプリケーションを開発することを念頭に作られている。JavaScriptのフレームワークには珍しく、DIを採用している。(型が無いので変数名ドリブンで判断している)後、特に強力なのはビューとデータのバインドがシームレスという事だ。例えばある変数をテキストボックスにバインドしたとする。その変数に値を代入すれば、テキストボックの値も即時に変更される。逆もまた然りでテキストボックスの値をユーザが変更すれば変数の値も変わる。HTMLをテンプレートに使うというのは、他のテンプレートエンジンの様にscriptタグの中にテンプレートのHTMLを書いておいて、それを使うという形ではなく直に書いてあるHTMLをテンプレートとして扱うということだ。公式の実例としては以下。
<!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>
通常の静的なHTMLの様だが、肝となる部分に色を付けてみた。まずhtmlタグにng-app属性があり、この配下がAngularJSの管理配下となることを意味する。(恐らくAngularJS的にHTML構文を解析してテンプレート化、データのバインド処理を行なっているのだろう)次にテキストボックスのng-model属性とh1タグの間に入っている「{{yourName}}」はデータとビューをバインドさせる意味になっている。テキストボックスはng-model等で指定するが単なる文字は「{{」「}}」でバインドするデータを指定出来る。同じデータにバインドしているのでテキストボックスの値を変更すれば、変更したのと同時にリアルタイムで「{{yourName}}」の値も変わっていく。
これだけでは値が動的に変わるだけで、リストだったり表示、非表示の分岐が出来ない。当然そういう仕組は用意されていて、それを見ればHTMLがテンプレートという意味が理解出来るかもしれない。
<!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>
青字の部分を上から解説していくと、ng-controller属性はこのタグ配下はTodoCtrlが管理する領域である事を示す。TodoCtrlはコントローラで複雑な処理が必要な場合にロジックを記述する場所となる。その次の「{{remaining()}}」はTodoCtrlのremaining関数を呼び出して、その戻り値を表示するという意味になる。どういう形で関数を定義するかというと以下のような感じになる。
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);
});
};
}
コントローラにDIされる$scope変数に関数やら変数を紐付けるとテンプレート上で参照出来るようになるわけだ。なので次の「{{todos.length}}」 も「$scope.todos.length」ということになる。次のng-click属性はクリックイベント発生時に実行する処理を指定する。この場合はarchive関数が呼ばれる事となる。次の「ng-repeat」は繰り返しの指定で繰り返すリストと1要素を参照するための変数名を定義する。今回はtodosをループしてそのタグツリー上の下で参照する為の変数名はtodoとなる。このtodosという配列に要素を追加したり、削除すればliタグの内容もリアルタイムで増減する。この辺がHTMLをテンプレートとしているという事だと思う。次の青字はclass属性の中に(!)書かれている「{{todo.done}}」だ。こんなクラス名の文字列もリアルタイムで変更することが出来る。こういった芸当が出来るのはng-app配下を解析し、AngularJS的に管理できるようにしているに違いない。ng-submitもng-click同様submitイベント時に実行する処理を指定していることになる。
ちなみになぜAngularという名前なのかはHTMLがangular(尖った)なカッコを持っているかららしい。そして属性名のプレフィックスである「ng」は"ng"を読むとそれが"angular"の発音に近いからだそうだ。
上記以外にも、ルーティング機能やバリデーション、そしてサーバサイドとの連携もサポートしている。ひと通りドキュメントを読んだ感じでは非常に素晴らしいフーレムワークだと思う。ビューからサーバーサイドまでの処理をなるべくシームレスにかつ記述を少なくしているのを実感出来る。それと同時にEnd-to-endソリューションと謳うだけあって、ものすごく多機能、高機能でもある。AngularJSの機能をフルに使って作成したサイトがあったら是非見てみたいものだ。個人的にはBackbone.jsよりもAngularJSはオススメだと考えているので、何かJavaScriptのMVCフレームワークを触ってみようと考えている人がいたら試して見て欲しい。