ちょっと話題の記事

AngularJS 案件ふりかえり

2014.05.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

angularjs125title

4 ヶ月強続いた案件がひと段落したので、過去に投下した下記エントリを元に振り返ってみました。
https://dev.classmethod.jp/client-side/javascript/angularjs12xstartup/

angular.module() の戻り値をグローバル変数に格納した代償

以前、Angular モジュールをグローバル変数に格納するよう

var ns = ns || {};
ns.App = angular.module('testApp', …);

と記述していましたが、この記法を採用して ngmin が動かなくなる…という現象に遭いました。なので、Angular コンポーネント ( controller, service など ) を定義するときには、以下のように記述することにしました。

(function () {
    'use strict';
    angular.module('appName').xxxxxxx('componentName', …);
}());

ちなみに、 ngmin は Grunt タスク (grunt-ngmin) として自動化しています。

$provide サービスの理解、使い分け

以前

任意の通信処理やライブラリの利用などといった特定の処理単位で用意します。
似たような機能で Factory が存在しますが、使用せず Service で統一することを掟とします。

などと書きましたが、angular.js のソースを読んで検討した末、掟を設けて縛ることは止めました。結局 Factory のみ使用していたという結果になりましたが、今回の案件では厳密に使い分ける必要がなかったということです。

angular.js

…
function provider(name, provider_) {
  assertNotHasOwnProperty(name, 'service');
  if (isFunction(provider_) || isArray(provider_)) {
    provider_ = providerInjector.instantiate(provider_);
  }
  if (!provider_.$get) {
    throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
  }
  return providerCache[name + providerSuffix] = provider_;
}

function factory(name, factoryFn) {
  return provider(name, { $get: factoryFn });
}

function service(name, constructor) {
  return factory(name, ['$injector', function($injector) {
    return $injector.instantiate(constructor);
  }]);
}

function value(name, val) {
  return factory(name, valueFn(val));
}

function constant(name, value) {
  assertNotHasOwnProperty(name, 'constant');
  providerCache[name] = value;
  instanceCache[name] = value;
}

function decorator(serviceName, decorFn) {
  var origProvider = providerInjector.get(serviceName + providerSuffix),
      orig$get = origProvider.$get;

  origProvider.$get = function() {
    var origInstance = instanceInjector.invoke(orig$get, origProvider);
    return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
  };
}
…

今後、用途に応じて使い分けるケースに直面したときには、それぞれの特徴を正しく理解した上で使い分けましょう…ということで落ち着いています。

余談ですが、下記メモの解説を読むと、provider, factory, service に関して理解が深まると思います。

AngularJS - angular.jsメモ - Qiita

value も factory も service も、結局は provider の機能制限版のようなものなので、
よくわからない場合は factory だけ使っていれば済むと思います。

ディレクティブの設計

コントローラでは捌ききれない DOM 操作や、jQuery UI ウィジェットのラッパー…などといった目的でいくつか作りましたが、それぞれ要件ごとに実装のお作法が異なり、統一されたルールを設けることは難しいと感じました。

なので、最低限のお約束事として

  • ディレクティブの命名規則
  • CSS セレクタの命名規則
  • 依存するスコープのモデル名の規則、管理

を徹底することを意識しておく以外は、特に縛りません…という程度にとどめています。

スコープのモデル設計

画面のデザイン / 遷移仕様に振り回されやすいので、下記については早めに決めておいた方が良いと思いました。

  • ngView ( $routeProvider のルーティング ) 管轄外に置かなければならないビューのモデル設計
  • ngInclude で動的に切り替わるビューのモデル設計
  • $scope.$emit, $scope.$broadcast で伝播させるイベント名のルール決め

まとめ

実務レベルで弄らないと気付けないことが意外と多くて困りました。( 苦笑
本エントリに書ききれなかったバッドノウハウや開発環境についてはまた別の機会に。