AngularJS で Underscore.js を使ってみた

AngularJS にユーティリティ関数あるにはあるけど、配列やオブジェクトを操作する関数が足りないので、 Underscore.js を使うことにした。

AngularJS らしく依存性注入したいから、Underscope.js を AngularJS モジュール化している。

<!DOCTYPE html>
<html ng-app="UnderscoreSample">
  <head>
    <meta charset="utf-8">
    <title>UnderscoreSample</title>
  </head>
  <body ng-controller="MainCtrl">
    <ul>
      <li ng-repeat="value in values" ng-bind="value"></li>
    </ul>

    <script src="underscore.js"></script>
    <script src="angular.js"></script>
    <script>
      // underscore をモジュール化
      angular.module("underscore", []).factory("_", function() {
          return _;
      });

      var app = angular.module("UnderscoreSample", ["underscore"]);

      // モジュール化した Underscore を使っていることがわかるように、$_ にしておく。
      // 実際は _ で使っている。
      app.controller("MainCtrl", ["$scope", "_", function($scope, $_) {
          var src = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

          // 偶数だけを表示する
          $scope.values = $_.filter(src, function(n) {
            return n % 2 === 0;
          });
      }]);
    </script>
  </body>
</html>

余談だけど、angular-underscore というライブラリがある。

こいつはフィルタも提供してくれるんだけど、フィルタは今のところ必要としていないのと、 $rootScope に Underscore の関数を生やすのが個人的に気に入らないので、導入は見送った。

AngularJS のテンプレートを入れ子にしたかったから angular-ui-router を使ってみた

AngularJS でテンプレートを入れ子にしたかったけど、ng-view は入れ子にできない。 つまり AngularJS の機能だけでは困難。 おまけに ng-view は複数置いて、別々のテンプレートを表示することもできないときた。

そんな ng-view や ngRoute に置き換わるのを目指したモジュールで、angular-ui-router がある。

こいつを使えばできそう。論よりコード。

<!DOCTYPE html>
<html ng-app="UIRouterSample">
  <head>
    <meta charset="utf-8">
    <title>UIRouterSample</title>
  </head>
  <body ng-controller="MainCtrl">
    <ul>
      <li ng-repeat="label in labels">
        <a ui-sref="label({ labelName: label.name })" ng-bind="label.name"></a>
      </li>
    </ul>
    <div ui-view></div>

    <script id="mails_template" type="text/ng-template">
      <table class="table">
        <thead>
          <tr>
            <th>Title</th>
          </tr>
        </thead>
        <tbody>
          <tr ng-repeat="mail in mails">
            <td><a ui-sref=".thread({mailId:mail.id})" ng-bind="mail.title"></a></td>
          </tr>
        </tbody>
      </table>
      <div ui-view></div>
    </script>

    <script id="thread_template" type="text/ng-template">
      <table class="table">
        <thead>
          <tr>
            <th>Title</th>
            <th>Message</th>
          </tr>
        </thead>
        <tbody>
          <tr ng-repeat="mail in mails">
            <td ng-bind="mail.title"></td>
            <td ng-bind="mail.message"></td>
          </tr>
        </tbody>
      </table>
    </script>

    <script src="angular.js"></script>
    <script src="angular-ui-router.js"></script>
    <script>
      // ui.router を使う
      window.App = angular.module("UIRouterSample", ["ui.router"]);

      App.controller("MainCtrl", ["$scope", function($scope) {
        $scope.labels = [
          { id: 1, name: "today" },
          { id: 2, name: "someday" },
          { id: 3, name: "scheduled" }
        ];
      }]);

      // $stateParams からパラメータを取り出せる
      App.controller("MailsCtrl", ["$scope", "$stateParams", function($scope, $stateParams) {
        var prefix = $stateParams.labelName + "_";
        $scope.mails = [
          { id: 1, title: prefix + "aaaaaa" },
          { id: 2, title: prefix + "bbbbbb" },
          { id: 3, title: prefix + "cccccc" }
        ];
      }]);
      App.controller("ThreadCtrl", ["$scope", "$stateParams", function($scope, $stateParams) {
          var prefix = "mail" + $stateParams.mailId + "_";
          $scope.mails = [
            { id: 1, title: "aaaaaa", message: prefix + "hogehoge" },
            { id: 2, title: "bbbbbb", message: prefix + "fugafuga" },
            { id: 3, title: "cccccc", message: prefix + "foobar" }
          ];
      }]);

      // ステートを登録
      // URL・コントローラー・テンプレートのセットに名前を付ける
      App.config(["$stateProvider", "$urlRouterProvider", function($stateProvider, $urlRouterProvider) {
        $stateProvider.
          state("label", {
            url: "/labels/{labelName:[a-zA-Z]+}",
            controller: "MailsCtrl",
            templateUrl: "mails_template"
          }).
          state("label.thread", {
            url: "/thread/{mailId:[0-9]+}",
            controller: "ThreadCtrl",
            templateUrl: "thread_template"
          });
      }]);
    </script>
  </body>
</html>

URL とコントローラーとテンプレートをセットにして「ステート」として扱っている。 ステートというより、Django のエンドポイントに近い気がする。 名前から URL を逆引きできるし。

angular-ui-router を AngularJS 本体に組み込む、なんて動きもあるみたいだけど、 早く進めて欲しいところだ。

天ぷら だるま

福岡市で天ぷらといったら「ひらお」が人気なんだけど、 大名にある「だるま」もグルメ本にちょくちょく載っていて気になっていたので、 週末行ってみた。

天ぷら定食 (800 円) を注文。

f:id:griefworker:20140531112541j:plain

まずはご飯とつゆ。大根おろしは少なめ。

f:id:griefworker:20140531112929j:plain

味噌汁。味噌汁は魚介のアラを使っているのか、いい出汁が出ていて旨い。

f:id:griefworker:20140531112719j:plain

最初の魚。

f:id:griefworker:20140531112844j:plain

海老。身がプリップリだった。

f:id:griefworker:20140531113128j:plain

魚その二。

f:id:griefworker:20140531113009j:plain

茄子。デカイ。ジューシーすぎて、汁で口の中やけどした。

f:id:griefworker:20140531113256j:plain

最後はイカ。実が柔らかくて、簡単に噛み切れた。

天ぷらは以上の5品。味は良かったけど、食べ足りない。 値段も 800 円と品数に対して高め。 いや、天ぷら定食 800 円って傍目に見れば安いけど、どうしてもひらおと比べてしまう。 正直なところ、同じ値段払うなら、ひらおに行くだろうな。

関連ランキング:天ぷら | 赤坂駅薬院大通駅西鉄福岡駅(天神)

蒙古タンメン中本

蒙古タンメン中本蒙古タンメンを食べてきた。麺屋武蔵と並んで、ずっと行きたいと思っていて、ようやく念願叶った。

f:id:griefworker:20140529110440j:plain

これがその『蒙古タンメン(800円)』。

味噌ベースのスープに辛口のマーボー麻婆豆腐がのっていた。 麻婆豆腐は結構辛いけど、スープはピリ辛程度なので、二つが混ざると調度いい感じに。 野菜はお鍋の具みたいにトロットロに煮込まれており、麻婆豆腐の餡と一緒に、 ちゃんぽん麺のようなモチモチ太麺に絡んで旨かった。

関連ランキング:ラーメン | 品川駅北品川駅高輪台駅

angular-mocks でモックが返すデータを動的に決める

angular-mocks をスタブとして使ってフロントエンドを開発していて、 ずっと

angular.module("sampleApp").run(["$httpBackend", function($httpBackend) {
  $httpBackend.whenGET("/users").respond([
    { id: 1, name: "香川" },
    { id: 2, name: "本田" },
    { id: 3, name: "長友" }
  ]);
}]);

という感じで決まったデータを返していた。

だけど、ソースコードを読んでいたら

angular.module("sampleApp").run(["$httpBackend", function($httpBackend) {
  var users = [
    { id: 1, name: "香川" },
    { id: 2, name: "本田" },
    { id: 3, name: "長友" }
  ];
  $httpBackend.whenGET("/users").respond(function() {
    return [200, users, {}];
  });
}]);

という風にして、動的に返すデータを変更できることに、今さら気付いた。 関数が返す配列にデータだけでなく、ステータスコードやヘッダーを含めるのがポイント。

以前試しに respond に function を渡したことがあって、そのときはデータだけ返していたから上手くいかなかったのか。 諦めずにソースコードまで追っていれば、もっと早く気付けたと思うと悔しい。

iPhone5 が新品になった

今使っている iPhone5 が電源ボタン無償交換プログラム対象に該当したので、 天神の AppleStore に予約してから行って来た。 ジーニアスバー初体験。

ボタンだけ交換じゃなくて、本体交換だったら良かったのになぁ、なんて思っていたら、 どうもボタンだけ交換なのはサポート延長していない人が対象だったみたい。 サポート延長していた自分は、新品の iPhone5 に交換とのこと。

iPhone5 が新品になったので、ケースと液晶フィルムを新調したくなった。 もうすぐサポート期間が終わるので、できるだけケースは衝撃に強いやつがいい。 液晶フィルムもガラスフィルムがいい。

天神パルコの AppBank ショップで 30 分ほど悩んで、次の 2 つを購入した。

ケースは店員さんの説明によると、アメリカ軍の基準をクリアしたケースらしい。 なるほど、強そうな外見をしてらっしゃる。

液晶フィルムはガラスフィルムにした。 万が一、液晶側から落としてしまった場合、こいつが変わりに割れてくれるハズだから、 そのときはガラスフィルムを買い直せば済む。

2つで合計 7360 円。 AppleCare有償修理したのと変わらない金額になってしまったな…。

ニクゼン

福岡の情報番組に出て有名になった『ニクゼン』に行ってきた。 開店 10 分前に着いたけど、既に結構な行列。 席に案内されるまで 30 分くらい待つことに。

f:id:griefworker:20140519192744j:plain

お目当てはステーキ丼ダブル 780 円

f:id:griefworker:20140519192801j:plain

プラス 100 円でご飯を大盛りにできる。 当然大盛りで。

まずはお吸い物。

f:id:griefworker:20140519192830j:plain

朝食を抜いていて空腹だったので染みた。

そしてお待ちかねのステーキ丼。

f:id:griefworker:20140519192842j:plain

ステーキ2枚分。なかなかのボリューム。 肉が赤身なのと、ワサビのおかげで、見た目に反してさっぱりと食べられた。 次々と箸が進んで、気が付けば丼が空に。

780 円でステーキを2枚分食べることができて、満腹で満足。 非常に気に入ったので、また食べに行きたいところだけど、あの行列に並ぶのは気が引けるなぁ。 これから暑くなるし。涼しくなってからにしよう。

関連ランキング:焼肉 | 赤坂駅天神駅西鉄福岡駅(天神)