AngularJSのTutorialのstep-7よりRoutingの仕組み

AngularJSの[Tutorial](http://docs.angularjs.org/tutorial/)のRoutingの仕組みを扱う[step-7](http://docs.angularjs.org/tutorial/step_07)を実施したレポートです。

クライアントフレームワークの重要な仕組みになるRoutingです。
[step-1](http://docs.angularjs.org/tutorial/step_01)からここまでのstepを理解して使えるようになると、コーポレートサイトなどを作るにあたってはMongoDBとAngularJSさえ揃えば必要十分なサイトを構築できます。
しかし、ユーザー認証が必要なポータルサイトや基幹アプリを製造するにはAngularだけでなくサーバの仕組みがが必要になってきます。本Advent Calenderの別ページにおいてサーバ側に必要な仕組みやインストール方法が親切に解説されていますのでそちらを参照してください。

> JSでページを動的に変更した場合、ブラウザの戻るや進むの仕組みは使えないことが多いですが、Angularのroutingの仕組みを利用した場合はそういった心配はないようです(他のJavascriptフレームワークも同じなのかもしれませんが)。

## [step-7](http://docs.angularjs.org/tutorial/step_07)

サーバ側の今時のフレームワークには必ず標準実装されているRoutingの仕組み。
これをクライアント側で実現するAngularの仕組みについて触れているデモスクリプトをもとに課題を遂行するのが[step-7](http://docs.angularjs.org/tutorial/step_07)になります。

### App Module

Routingを利用するには、ngRouteモジュールが導入されている必要があります。

```js:app/js/app.js
var phonecatApp = angular.module('phonecatApp', [
  'ngRoute',
  'phonecatControllers'
]);
```

上記は、ng-appディレクティブで指定されたモジュールに対して、ngRouteモジュールを導入した記述部分になります。
こうすることで下記のようにRouting設定を$routeProviderサービスを利用して記述できるようになります。

```js:app/js/app.js
phonecatApp.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/phones', {
        templateUrl: 'partials/phone-list.html',
        controller: 'PhoneListCtrl'
      }).
      when('/phones/:phoneId', {
        templateUrl: 'partials/phone-detail.html',
        controller: 'PhoneDetailCtrl'
      }).
      otherwise({
        redirectTo: '/phones'
      });
  }]);
```

上記は、phonecatAppというアプリケーションモジュールに対して、configメソッドでRouting設定を実装しています。実装するにあたっては$routeProviderサービスを利用しています。
そして、whenメソッドを使って、ユーザ側に要求するURI設定と要求された後に利用するControllerの[deep linking](http://en.wikipedia.org/wiki/Deep_linking)の仕組みを実現しています。

### テンプレート


git でcheckoutして、index.htmlを参照するとこれまで記述されていたリスト出力や検索のDOM記述が一切なくなっているのがわかります。このindex.htmlは、Angularの資料内では「layout template」と呼ばれるテンプレートです。
そして、ようやく実際のアプリっぽくなってきました。ページ内のリソースを出力するテンプレート（partial templateと呼ばれるようです）は、app/partialsという場所に保存されています。

重要な変更点としては下記の通り、ng-appディレクティブにアプリケーションモジュール指定がなされていたのですが、app/js/app.jsで初めてこのアプリケーションモジュールに対して設定記述が追加されたところです。

```html:app/index.html
<html lang="en" ng-app="phonecatApp">
```

phonecatAppは、app/js/app.jsで定義されたアプリケーションモジュールになります。

また、Routingを利用するために下記のscriptタグが追記されています。

```html:app/index.html
<script src="lib/angular/angular-route.js">
```

一般的なControllerの話をするとき、大概の場合、ActionというControllerのさらに下層の存在について考える必要があります。たまにControllerと言っていてMVC的に画面を出力する仕組みを表しているのかフィーチャそのものを表しているのか分からなくなります。それと比較して、AngularのControllerはシンプルに画面出力する仕組みを表現しており、ControllersがControllerを束ねる存在になっていてわかりやすい。

これまで気にしていなかったですが、[module](http://docs.angularjs.org/guide/module)という存在に触れられています。
AngularでModuleとして実装された場合、controllerだけでなくfilterだったり、configだったり、あらゆるものを梱包される存在です。そのため、プロダクトの規模が大きくなってきた場合には、目的に応じてModuleを分割して定義することが良いようです。たとえば、Controllersモジュールをカテゴライズされた画面グループ単位で分けたり、オリジナルのservice用のモジュールだったり、オリジナルのdirectiveだったりなどです。
サンプルでは、画面数が少ないため、シンプル構成で、Controllerモジュールは一つしか作らないようです。

### Test

テストはこれまでのstepで説明されているテストの応用であるため、説明されずデモスクリプト側を参照する形になっています。

```ｊｓ:test/unit/controllersSpec.js
    it('should display placeholder page with phoneId', function() {
      expect(binding('phoneId')).toBe('nexus-s');
    });
```

一点、今回シンプルな詳細ページが追加されたテストのデモテストコードが表示されています。
ここで、Angularのテストがしやすい点を見つけました。テスト時に詳細画面の表示データ確認は、Templateに埋め込まれる変数をBindingして、正しいか確認しています。
私のSeleniumなどの経験からすると、表示されているデータを確認する場合、次のどちらかを使って確認します。

* テスト用に画面内にユニークとなる文字列を表示させるようにしてassertContainsなどで調べる
* もしくは、チェックするターゲットタグのid属性かclass属性などを指定して要素の値を調べる

しかし、Angularは、「出力する変数名のところに期待値が表示されていること」というふうに書くだけでいいのです。
テストしやすいですね。


以上、AngularのRoutingの仕組みのstepレポートでした。