RouterはAngularJSのルーティングモジュール。階層化されたviewを利用することなどができる。最終的なプロジェクトの目標はngRouteに取って代わって標準搭載されることだそうで、AngularJS本体も興味を示しているらしい(GitHubのwikiに書いてある)。触ってみて、実際の使い方に触れた解説記事は少ないようなのでざっくり使い方を書く。https://github.com/angular-ui/ui-router/wikiちなみに上記の公式のwikiを読めば分かることしか書いてない。あとQiitaに抜粋版を書いたので、細かい説明が要らない人はたぶんそっちのがわかりやすい。Qiitaサンプル以下でやっていることをだいたい盛り込んだサンプルがこれ。右側のメニューのCodeを押せば各ファイルが、Editを押せばPlunkerで編集できる。Plunkerでいろいろコードを変えてみたりして試してみるとわかりやすいかもしれない(知ってると思うけど、Plunkerで編集したりしても別にこっちのサンプルが壊れたりしないので安心していい)いちいち対応させて説明することはしない。つかいかたモジュールなので、ダウンロードしたら普通のモジュールと同じように読み込む。Ver1.2から標準のルーティング機能もモジュール化されてる。そっからの移行だと、ngRouteを読み込む部分をui.routerに書き換えればいい。ui-viewのような感じで置き換える。メソッド名は同じにしてあるところもあり、使いまわせるところもある。$routeParamsなんかは、$stateParamsに置き換えるだけで使える。ちなみに$locationProvider(html5Mode設定するやつ)はngRouteと関係ないのでそのまま。$stateProvider$stateProviderのstateメソッドでルーティングの設定をする。ngRouteでの$routeProvider.whenを$stateProvider.stateに置き換える。設定はぱっと見似たようなもんだけど、考え方はちょっと違う。ngRouteはシンプルで、特定のURLに来たらアプリ全体で唯一のng-viewに対して、指定のテンプレートとコントローラを埋め込むというだけのものだ。設定するのはURLとテンプレートおよびコントローラーの対応関係になる。それに対してui-routerはstate(状態)を設定する。stateがまず先にあり、そのstateに対応するURLを設定し、また、そのstateのとき、どのview(複数もあり得る)にテンプレートとコントローラーを当てるかという設定をする。stateは階層を持ち、ドットで区切って指定をする。itemsというstateを設定して、items.detailというstateを設定すると、items.detailはitemsの子として作成される。子として作成されると、viewで設定するテンプレートを表示する位置が親の内側になったり、URLが親のURLに続く感じになる。これは何も指定しなければそうなるというだけで、設定次第で変更できる(後述)。ngRouteはURLを基準にして動作するが、ui-routerはstateが基準になる。設定も以下のような感じになる。$stateProvider(state名,{設定})たとえば/emp/12345みたいなURLがあり、empだけなら社員一覧、12345が渡されたら詳細というような設計なら、以下のようなコードになる。});という感じになる。上でも書いてるがemp.detailはempの子なので、:empIDというUrlは、empのUrl(/emp)に続く。/emp/:empIDとなるので、ngRouteと同じURLになる。ngRouteの場合、すべてのテンプレートは常に単一のng-viewに表示されるが、ui-routerの場合この設定だとemp.htmlはlist.htmlの中のui-viewに表示される。一覧のリストのページの一部に詳細が表示されるような感じになる。先に書いたとおり、ngRouteと同じように単一のviewに表示することもできる。そのためには表示先のviewを指定すれば良い。そのためにはviewの名前の指定と、参照先のviewを絶対指定することが必要になるので、順に説明する。viewの名前付け表示先のviewは名前をつけることができ、これにより一度に複数指定したりできる。}}のように設定する。viewsは保持するプロパティ名がviewの名前に対応する。ちなみに最初のコードでは名前を指定していないが、それは以下の設定と同じだ。}}これでも問題なく動作する。ちなみにAngularJSの話からはやや脱線するがJavaScriptでプロパティ名に上記のような空文字やハイフン、アットマークなんかを使ったりするときは二重引用符(")で囲まないとエラーになる。何でそんなことを書くかと言うと、viewsのプロパティでアットマークを使えば、表示対象のviewの位置を親と関係なく絶対指定することができるためだ。URLの階層は常に対応するわけではない。ファイラーとか常に階層化された画面構造ならともかく、一番上のサンプルと同じように社員の一覧から、社員の詳細を選び、その社員の投稿した画像一覧をほぼ画面全域に展開したい、なんてことがありうる。その場合、URL上は親子関係があっても、画像一覧の画面は親の表示位置を上書きすることになる。(画像一覧ページが階層的に詳細の下に入る必要はないとかいうことはさておく)(さておくけど、うまい設計なら良い感じに階層化できるのかもしれない)ともかく、viewsのプロパティ名は単純に名前だけ指定すると、親の持つビュー名になる。ビュー名@ステート名のように書けば、直接表示対象のビューを指定できる。ちなみにビュー名@で終わる場合は、一番上位の階層のui-viewになる。上位階層のビューが名前無しの場合、ただ"@"で指定することができる。各ステートの名前無しビューは、"@ステート名"という形で指定する。}}このコードだと、empの持つ名前無しのビューに表示される。現在emp.detailが表示されている位置が差し替えられる。設定側で書きたいことはだいたい書けたのであとは適当に列挙。詳しくは公式のWikiを見てね。抽象(abstract)指定で親になるが指定はできないステートとか作れる。urlは{id:[0-9]{5}}みたいに正規表現指定できる。urlは^から始めると絶対指定で最上位から始められる。これ移動時にstate指定するときの^(親のステート)と同文字で意味が違ってわかりにくい気がする。今まで設定したルートを利用する場合、つまりアンカータグ(a)なんか移動するときは、ui-srefディレクティブを使う。#/hogeみたいにhrefとかng-hrefに書いても正しく動作するんだけど、それだとhtml5Modeを切り替えたりURLの構造を変えた時に全部書きなおすことになる。ui-srefはステートとパラメータを渡しておけば、あとのURL構造の変更とかhtml5Modeへの対応なんかは勝手にやってくれる。ui-sref=".hoge({id:empID})"...>これも相対パスと絶対パスがあって、この例だと現在のstate直下のhogeというstateに移動する。ドットが頭に付くと相対パスで、ドットが無ければ絶対パスで、^から始まると親のステートとか、そんな感じ。詳しくはWikiを参照のこと。引数で渡すオブジェクトのプロパティ名は当然設定したときにurlが受け取るパラメータ名と一致していないとならない。ui-sref-activeにそのステートがアクティブなときに付けたいクラスを指定すると、上のサンプルみたいにbootstrapのactiveなんかを簡単に利用できるので何かと楽。ng-classと違って、普通のclass指定とも共存するので便利。ちなみにコード上から移動するときは$state.go()を利用する。PLUGSという耳栓を海外から買った。