aboutsummaryrefslogtreecommitdiffstats
path: root/docs/content/guide/services.ngdoc
blob: bc2a4f85d1433915d5f704f316849670078883e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
@ngdoc overview
@name  Services
@description

# Services

Angular services are substitutable objects that are wired together using {@link di dependency
injection (DI)}. You can use services to organize and share code across your app.

Angular services are:

* Lazily instantiated  Angular only instantiates a service when an application component depends
  on it.
* Singletons  Each component dependent on a service gets a reference to the single instance
  generated by the service factory.

Angular offers several useful services (like {@link ng.$http `$http`}), but for most applications
you'll also want to {@link services#creating-services create your own}.

<div class="alert alert-info">
**Note:** Like other core Angular identifiers built-in services always start with `$`
(e.g. `$http`).
</div>


## Using a Service

To use an Angular service, you add it as a dependency for the component (controller, service,
filter or directive) that depends on the service. Angular's {@link di dependency injection}
subsystem takes care of the rest.

<example module="myServiceModule">
  <file name="index.html">
    <div id="simple" 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>
  </file>

  <file name="script.js">
    angular.
     module('myServiceModule', []).
      controller('MyController', ['$scope','notify', function ($scope, notify) {
        $scope.callNotify = function(msg) {
          notify(msg);
        };
      }]).
     factory('notify', ['$window', function(win) {
        var msgs = [];
        return function(msg) {
          msgs.push(msg);
          if (msgs.length == 3) {
            win.alert(msgs.join("\n"));
            msgs = [];
          }
        };
      }]);
  </file>

  <file name="protractor.js" type="protractor">
    it('should test service', function() {
      expect(element(by.id('simple')).element(by.model('message')).getAttribute('value'))
          .toEqual('test');
    });
  </file>
</example>

<div class="alert alert-info">
**Note:** Angular uses
[**constructor injection**](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/).
</div>

### Explicit Dependency Injection

A component should explicitly define its dependencies using one of the {@link di injection
annotation} methods:

1. Inline array injection annotation (preferred):
  ```js
  myModule.controller('MyController', ['$location', function($location) { ... }]);
  ```

2. `$inject` property:
  ```js
  var MyController = function($location) { ... };
  MyController.$inject = ['$location'];
  myModule.controller('MyController', MyController);
  ```

<div class="alert alert-success">
**Best Practice:** Use the array annotation shown above.
</div>

### Implicit Dependency Injection

Even if you don't annotate your dependencies, Angular's DI can determine the dependency from the
name of the parameter. Let's rewrite the above example to show the use of this implicit dependency
injection of `$window`, `$scope`, and our `notify` service:

<example module="myServiceModuleDI">
  <file name="index.html">
    <div id="implicit" ng-controller="MyController">
      <p>Let's try the notify service, that is implicitly 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>
  </file>

  <file name="script.js">
    angular.module('myServiceModuleDI', []).
      factory('notify', function($window) {
        var msgs = [];
        return function(msg) {
          msgs.push(msg);
          if (msgs.length == 3) {
            $window.alert(msgs.join("\n"));
            msgs = [];
          }
        };
      }).
      controller('MyController', function($scope, notify) {
        $scope.callNotify = function(msg) {
          notify(msg);
        };
      });
  </file>
</example>

<div class="alert alert-danger">
**Careful:** If you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming) your code,
your variable names will get renamed unless you use one of the annotation techniques above.
</div>


## Creating Services

Application developers are free to define their own services by registering the service's name and
**service factory function**, with an Angular module.

The **service factory function** generates the single object or function that represents the
service to the rest of the application. The object or function returned by the service is
injected into any component (controller, service, filter or directive) that specifies a dependency
on the service.

### Registering Services

Services are registered to modules via the {@link angular.Module Module API}.
Typically you use the {@link angular.module Module#factory} API to register a service:

```javascript
var myModule = angular.module('myModule', []);
myModule.factory('serviceId', function() {
  var shinyNewServiceInstance;
  //factory function body that constructs shinyNewServiceInstance
  return shinyNewServiceInstance;
});
```

Note that you are not registering a **service instance**, but rather a **factory function** that
will create this instance when called.

### Dependencies

Services can have their own dependencies. Just like declaring dependencies in a controller, you
declare dependencies by specifying them in the service's factory function signature.

The example module below has two services, each with various dependencies:

```js
var batchModule = angular.module('batchModule', []);

/**
 * The `batchLog` service allows for messages to be queued in memory and flushed
 * to the console.log every 50 seconds.
 *
 * @param {*} message Message to be logged.
 */
batchModule.factory('batchLog', ['$interval', '$log', function($interval, $log) {
  var messageQueue = [];

  function log() {
    if (messageQueue.length) {
      $log.log('batchLog messages: ', messageQueue);
      messageQueue = [];
    }
  }

  // start periodic checking
  $interval(log, 50000);

  return function(message) {
    messageQueue.push(message);
  }
}]);

/**
 * `routeTemplateMonitor` monitors each `$route` change and logs the current
 * template via the `batchLog` service.
 */
batchModule.factory('routeTemplateMonitor', ['$route', 'batchLog', '$rootScope',
  function($route, batchLog, $rootScope) {
    $rootScope.$on('$routeChangeSuccess', function() {
      batchLog($route.current ? $route.current.template : null);
    });
  }]);

```

In the example, note that:

* The `batchLog` service depends on the built-in {@link ng.$interval `$interval`} and
  {@link ng.$log `$log`} services.
* The `routeTemplateMonitor` service depends on the built-in {@link ngRoute.$route `$route`}
  service and our custom `batchLog` service.
* Both services use the array notation to declare their dependencies.
* The order of identifiers in the array is the same as the order of argument
  names in the factory function.

### Registering a Service with `$provide`

You can also register services via the {@link auto.$provide `$provide`} service inside of a
module's `config` function:

```javascript
angular.module('myModule', []).config(function($provide) {
  $provide.factory('serviceId', function() {
    var shinyNewServiceInstance;
    //factory function body that constructs shinyNewServiceInstance
    return shinyNewServiceInstance;
  });
});
```

This technique is often used in unit tests to mock out a service's dependencies.


## Unit Testing

The following is a unit test for the `notify` service from the {@link services#creating-services
Creating Angular Services} example above. The unit test example uses a Jasmine spy (mock) instead
of a real browser alert.

```js
var mock, notify;

beforeEach(function() {
  mock = {alert: jasmine.createSpy()};

  module(function($provide) {
    $provide.value('$window', mock);
  });

  inject(function($injector) {
    notify = $injector.get('notify');
  });
});

it('should not alert first two notifications', function() {
  notify('one');
  notify('two');

  expect(mock.alert).not.toHaveBeenCalled();
});

it('should alert all after third notification', function() {
  notify('one');
  notify('two');
  notify('three');

  expect(mock.alert).toHaveBeenCalledWith("one\ntwo\nthree");
});

it('should clear messages after alert', function() {
  notify('one');
  notify('two');
  notify('third');
  notify('more');
  notify('two');
  notify('third');

  expect(mock.alert.callCount).toEqual(2);
  expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]);
});
```


## Related Topics

* {@link guide/di Dependency Injection in AngularJS}

## Related API

* {@link ./ng Angular Service API}
* {@link angular.injector Injector API}