のらねこの気まま暮らし

技術系だけど、Qiita向きではないポエムとかを書くめったに更新されないヤツ

AngularJS x UI-Routerの使い方

UI-Routerはとても強力で、ngRouterよりも多くの事ができるのでとても便利。 しかし、強力すぎてRouterの概念自体を塗り替えてしまっていてなかなかピンと来てなかったのでまとめてみる。

リストページと詳細ページを別々のページとして用意する

state-router.js

app.config(["$stateProvider", function ($stateProvider) {
    $stateProvider
        .state("list", {
            "url": "^/list",
            "templateUrl": "list.html",
            "controller": "ListCtrl"
        })
        .state("detail", {
            "url": "^/detail/:detail_id",
            "templateUrl": "detail.html",
            "controller": "DetailCtrl"
        })
     ;
}])

index.html

<div ui-view></div>

list.html

<ul ng-repeat="content in contents">
  <li><a href="#/detail/{{content.id}}">{{content.title}}</a></li>
</ul>

detail.html

<dl>
  <dt>ID</dt>
  <dd>{{detail.id}}</dd>
  <dt>Title</dt>
  <dd>{{detail.title}}</dd>
</dl>

リストと詳細がひとつのページの中にある

2カラムレイアウトでlistとdeitalを同じページの中に内包する。

state-router.js

app.config(["$stateProvider", function ($stateProvider) {
    $stateProvider
        .state("contents", {
            "templateUrl": "contents.html",
            "controller": "ContentsCtrl"
        })
        .state("contents.detail", {
            "views": {
                "detail@contents": {
                    "templateUrl": "detail.html",
                    "controller": "DetailCtrl"
                }
            }
        })
    ;
}])

index.html

<div ui-view></div>

list.html

<nav class="left-column">
  <ul ng-repeat="content in contents">
    <li><a ui-sref="contents.detail({id: content.id})">{{content.title}}</a></li>
  </ul>
</nav>

<div class="right-column" ng-view="detail">

detail.html

<dl>
  <dt>ID</dt>
  <dd>{{detail.id}}</dd>
  <dt>Title</dt>
  <dd>{{detail.title}}</dd>
</dl>

2カラムレイアウトでdetailをURLで指定できるようにする

/contentでリストとindexを、/content/{detail_id}で指定したdetailを表示できるようにする。

state-router.js

app.config(["$stateProvider", function ($stateProvider) {
    $stateProvider
        .state("contents", {
            "url": "^/content",
            "templateUrl": "contents.html",
            "controller": "ContentsCtrl"
        })
        .state("contents.detail", {
            "url": "/:id"
            "views": {
                "detail@contents": {
                    "templateUrl": "detail.html",
                    "controller": "DetailCtrl"
                }
            }
        })
    ;
}])

まとめ

  • stateは継承が可能
    • .で連結することで、親.子というstateを定義できる
  • viewsにビュー@ステートを指定すると、親ステートで定義したui-viewにtemplateを埋め込むことができる
  • stateをネストした場合、URLは親のURLに追加される形で指定できる
    • ^からURLを開始する(^/content/:detailというように)ことで相対ではなく絶対パスで指定できる
  • hrefの代わりに、ui-sref属性を用いることで、URLではなくstateをリンクに指定できる。
    • ui-srefを利用するばあい、$stateProviderに定義されてないstateを指定するとリンクにならない

UI-Routerの理解に一日費やしたので、とりあえず僕の理解の範囲をまとめた。 ややこしいけど大変便利!

AngularJSでdirectiveを作ってみる

2014-03-25っていう文字列の日付をyear, month, dayの3つのフォームに分割して入力したい、と思った。

一つのngModelからフォーマットを変えてinputを並べればいいとおもって、directiveを使ってみた記録。

<input type="date" name="year"     ng-model="user.birth_on">
<input type="date" name="month" ng-model="user.birth_on">
<input type="date" name="day"     ng-model="user.birth_on">

directiveの作り方

ngModelController$formattersというプロパティがArrayで存在するので、そいつにフォーマット用のfunctionを登録してやる。

  • $filterを利用してdateを整形する
  • 整形文字列は、ui-date-formatの属性で指定できるようにする
    • 例)ui-date-format="yyyy"
  • フォーマットする文字列はmodelから取ってくる
angular.module("app")
  .directive("uiDateFormat", [
    "$filter",
    function ($filter) {
      return {
        restrict: "A",
        require: "ngModel",
        link: function (scope, element, attrs, ctrl) {
          ctrl.$formatters.push(function (view_value) {
            return $filter("date")(view_value, attrs.uiDateFormat);
          });
        }
    }
  ]);
<input type="date" name="year"     ng-model="user.birth_on" ui-date-format="yyyy">
<input type="date" name="month" ng-model="user.birth_on" ui-date-format="M">
<input type="date" name="day"     ng-model="user.birth_on" ui-date-format="d">

ui-dateというAngular UIのライブラリ

ui-dateを使えばいいという気はしつつ、ui-dateはjquery-uiとjqueryに依存しているし、そこまでの機能は必要なさそうだった。 なので、勉強を兼ねて作ってみた。