9a9b07dea8
The quotes rule had to be disabled for e2e tests generated from ngdoc
because dgeni templates use double quotes as string delimiters.
Since we can't have guarantees that dgeni template wrappers will follow
the same JS code style the Angular 1 repo uses, we should find a way
to enforce our ESLint setup only for the parts in this repo, perhaps
via prepending a generated `/* eslint-enable OUR_RULES */` pragma.
(partially cherry-picked from 9360aa2d27)
Closes #15011
238 lines
6.9 KiB
Plaintext
238 lines
6.9 KiB
Plaintext
@ngdoc overview
|
||
@name Services
|
||
@sortOrder 230
|
||
@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" name="services-usage">
|
||
<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>
|
||
|
||
|
||
## 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#factory Module factory} API to register a service:
|
||
|
||
```js
|
||
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.
|
||
|
||
For more on dependencies, see the {@link guide/di dependency injection} docs.
|
||
|
||
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) {
|
||
return {
|
||
startMonitoring: function() {
|
||
$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:
|
||
|
||
```js
|
||
angular.module('myModule', []).config(['$provide', 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(module('myServiceModule'));
|
||
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 ./api/ng/service Angular Service API}
|
||
* {@link angular.injector Injector API}
|