コンポーネントの作成
先ほどパスとコンポーネント名だけを指定しましたが、これではあまりにも設定が少なすぎると思った方もいるのではないでしょうか。
ngNewRouterではコントローラ名とテンプレートファイル名に命名規則があります。例えば、homeというコンポーネント名であれば、コントローラ名は「HomeController」という名称である必要があり、HTMLのテンプレートファイルは、components/home/home.htmlというファイル名である必要があります。
コントローラを定義するファイル名は特に決まりはありませんが、今回は公式サンプルと同様にコントローラもcomponents/home/home.jsに配置します。このようなルールは好みもありますが、まずはデフォルトのルールでできるだけ利用するようにしましょう。
続いてhomeコンポーネントを作成します。テンプレートファイルはリスト3のようになります。
<h1>Welcome HOME</h1>
<!-- (1) 他のコンポーネントへのリンク -->
<a ng-link="item({id: 342})">商品342へのリンク</a><br />
<!-- (2) データバインディングの利用 -->
<div>
<input type="text" ng-model="home.item_id"><br />
<a ng-link="item({id: home.item_id})">商品{{home.item_id}}へのリンク</a>
</div>
(1)のng-link属性を使って他のコンポーネントへのリンクを定義します。直接URLを使って、例えば「#/item/342」のように指定したくもなりますが、現在そのような指定での遷移はできないようです。
また、引数がない場合にはコンポーネント名だけで問題ありません。
続いて、コントローラ側と変数をバインドするときの例ですが、必ず変数のプレフィックスとしてコンポーネント名がつきます。
このあたりも好みが分かれる事でしょう。また、この影響はリスト4のようにコントローラを作成する際にもあります。
(function(module){
// (1) コントローラは別のモジュールでも同じモジュール内でも可能
module.controller('HomeController',[HomeController]);
function HomeController(){
// (2) $scopeは使えない。 thisに設定した値が自動的にバインディング対象になる
this.item_id = 123;
}
}(this.module));
まず、(1)ではHomeControllerを作成していますが、いつもの$scopeの指定はできません。
$scopeを指定するとngNewRouterではコントローラの作成に失敗します。原因がエラーメッセージに表示されないので注意しましょう。
このように、コンポーネント用のコントローラと今まで使っていたコントローラでは少々制限が違うようです。
また、$scopeが使えない代わりに(2)のようにthisを使います。今までも、「<div ng-controller="HomeController as home">」のようにコントローラを指定できましたが、同じような感じになるのかと思います。
続いて、パスからパラメータを取得する方法はリスト5のようになります。
(function(){
// (1) 別のモジュールとして作成することも可能
var module = angular.module('app.item',['ngNewRouter']);
// (2) URLハッシュ(/item/:id)からidパラメータを取得する
module.controller('ItemController',['$routeParams',function($routeParams){
this.id = $routeParams.id;
}]);
}());
homeコンポーネントはメインとなるモジュールに定義しましたが、(1)のように別のモジュールとして定義することももちろん可能です。その場合には、依存モジュールとして指定することを忘れないようにしてください。
パスから指定のパラメータを取得するには、(2)のように$routeParamsオブジェクトのプロパティとして取得できます。
また、どうしてもコンポーネントを作成する際のデフォルトのコントローラ名のルールや、テンプレートのファイルの命名規則を変えたい場合にはリスト6のように$componentLoaderProviderを利用して変更します。
記述してあるルールはデフォルトのルール実装になっていますので、それらを参考にして自分の好みにあったルールに変えることは比較的容易に行えます。
module.config(['$componentLoaderProvider', function ($componentLoaderProvider) {
$componentLoaderProvider.setComponentFromCtrlMapping(function(name){
// 新しいコントローラの命名規則を定義
var ret = name[0].toLowerCase() + name.substr(1, name.length - "Controller".length - 1);
return ret;
});
$componentLoaderProvider.setTemplateMapping(function(name){
// 新しいテンプレートファイルの命名規則を定義
var dashName = dashCase(name);
var ret = './components/' + dashName + '/' + dashName + '.html';
return ret;
});
}]);
複数のビューを表示する
これまでは1つのパスにつき1つのビューでしたが、ngNewRouterでは複数のビューとコンポーネントをセットにして、パスと連動して定義することができることが特徴的です。
ポータレット、もしくはウィジェットの集合であるダッシュボードのような画面が作りやすくなっていると感じました。
そのためか、実はng-viewportという命名は、現在の開発レベルではng-outletに変わろうとしていますのでngNewRouterではこの機能の特徴が名前にも現れているのではないかと思っています。
ただし、サンプルでは簡略化の為に図2のように共通するヘッダと異なる画面の表示にて説明します。
複数のビューの指定は、リスト7のようにng-viewportに必ず値を指定し名称を設定します。先ほどの例で名称を指定していませんでしたが、その場合にはdefaultとい名称を指定したことと同じになります。
<body ng-app="app">
<div ng-viewport="header"></div>
<div ng-viewport="main"></div>
</body>
続いて、コンポーネントの指定では先ほど指定した名称を利用し、リスト8のように指定します。
AppController.$routeConfig = [
{path: '/', redirectTo: '/home'},
{path: '/home' , components: { header : 'header' , main : 'home' }, as : 'home'},
{path: '/info' , components: { header : 'header', main : 'info' }, as : 'info'}
];
headerには共通の「header」コンポーネントを指定していますが、mainには別のコンポーネントを指定して表示を切り分ける事ができます。
また、複数のコンポーネントを指定している場合には、asを使ってng-linkで利用するリファレンス名を指定します。
コンポーネントの作成方法はこれまでと同様です。

