AngularJSのサービス#AngularJS入門その5

2014.05.22

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

AngularJSのサービス

AngularJSにおけるサービスとは、アプリにおいて任意のタスクを実行する関数として使用されます。
例えば、AngularJSではajax通信用に$http組み込みサービスを持っています。
もちろん、サービスを自分で定義して使用することも可能です。

AngularJSでビジネスロジックはサービスとして実装されることが推奨されているため、
独自サービスを作成する機会は多いと思います。
その独自サービスをAngularJSで作成するには複数の方法があるので、それらの方法を確認してみましょう。

今回使用した動作環境は以下のとおりです。
なお、本記事で紹介しているコードは、以前作成したangular-seedを使って動作を確認しました。

  • OS : MacOS X 10.9.2
  • node.js : 0.10.24
  • Git : 1.8.5.2

サービスを使う

AngularJSで独自定義のサービスを使用するには、Module#factoryを使用するか、
自分でモジュールconfig関数内部で$provideを使用してサービスを登録する必要があります。
また、すべてのサービスは前回解説したDIの仕組みを使用して登録することになります。

サービスを登録してみる

サービスを登録するには、そのサービスが全体の一部となるモジュールを持つようにします。
すると、モジュール用APIかconfig関数内の$provideサービスを使用してサービスを登録することができます。

//angular.Moduleを使用してサービス登録
var myModule = angular.module('myModule', []);
myModule.factory('myServiceId', function() {
  var myServiceInstance;
  /**
   *myServiceInstanceを作成.
   *ここでfactory関数を記述する
   */
  return myServiceInstance;
});

//$provideサービスを使用してサービス登録
angular.module('myModule', [], function($provide) {
  $provide.factory('myServiceId', function() {
    var myServiceInstance;
  /**
   *myServiceInstanceを作成.
   *ここでfactory関数を記述する
   */
    return myServiceInstance;
  });
});

サービスのインスタンスが登録されるわけではなく、サービスを作成するファクトリー関数が登録されます。

サービスの持つ機能

・依存性
サービスには依存性を指定することが可能です。ファクトリ関数の引数として指定すれば依存性を指定できます。
次の例は、AngularJS組み込みの$windowサービスに依存した関数を作成しています。
$windowサービスはfactoryによってファクトリー関数によってstackMessagesへ引数として引き渡されます。

//stackMessagesは受け取ったメッセージをスタックし、3つになったらアラート表示する
angular.module('myModule', [], function($provide) {
  $provide.factory('stackMessages', ['$window', function(win) {
    var msgArray = [];
    return function(msg) {
      msgArray.push(msg);
      if (msgs.length == 3) {
        win.alert(msgArray.join(""));
        msgArray = [];
      }
    };
  }]);
});

・サービスはシングルトン
AngularJSにおけるサービスは全てシングルトンになります。
インジェクター毎に与えられるサービスのインスタンスは、常に1つです。

・Angularサービスのインスタンス化
AngularJSの全てのサービスは、遅延してインスタンス化されます。そのため、サービスは必要になったときに
AngularJSによってインスタンス化されます。

コントローラでサービスを使う

サービスは、以前解説したAngularJSのコントローラへDIしてよく使用されます。
DIされるサービス名の文字列を含んだ配列の$injectプロパティを使用してサービス名を指定することが可能です。
サービス名は、AngularJSで登録されたサービスのIDと同じにしておく必要があります。
配列内のサービスの順番は、ファクトリー関数を呼び出す際に使用されます。

では公式ドキュメントサイトにあるを参考に、
コントローラとサービスを連携させたサンプルをつくってみます。
angular-seed/app/jsディレクトリにsample1.jsファイルを作成しましょう。

angular.
 module('MyServiceModule', []).
 factory('stackMessage', ['$window', function(win) {
    var msgs = [];
    return function(msg) {
      msgs.push(msg);
      if (msgs.length == 3) {
        win.alert(msgs.join("\n"));
        msgs = [];
      }
    };
  }]);
function myController(scope, notifyService) {
  scope.stackMessage = function(msg) {
    notifyService(msg);
  };
}
myController.$inject = ['$scope','stackMessage'];

MyServiceModuleでstackMessageサービス(関数)を作成し、myControllerにDIしています。
上記サービスとコントローラを使用するhtmlもappディレクトリにsample1.htmlという名前で作成します。

<!doctype html>
<html ng-app="MyServiceModule">
  <head>
    <script src="http://code.angularjs.org/1.2.3/angular.min.js"></script>
    <script src="js/sample1.js"></script>
  </head>
  <body>
    <div ng-controller="myController">
      <p>Let's try this simple notify service, injected into the controller...</p>
      <input ng-init="message='test'" ng-model="message" >
      <button ng-click="callNotify(message);">NOTIFY</button>
      <p>(you have to click 3 times to see an alert)</p>
    </div>
  </body>
</html>

ではサーバを起動し、ブラウザでアクセスしてみましょう。

% cd /path/your/angular-seed
% node scripts/web-server.js
Http Server running at http://localhost:8000/

http://localhost:8000/app/sample1.htmlにアクセスして動作を確認してみてください。

まとめ

今回は基本的なサービスの使い方について解説しました。
サービスの具体的な使い分け方についてはこちらもご確認ください。

参考サイトなど