mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-05-20 15:54:25 +08:00
docs(guide/services): rewrite services documentation
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Using $location
|
||||
@name Using $location
|
||||
@description
|
||||
|
||||
# What does it do?
|
||||
@@ -329,7 +329,7 @@ reload to the original link.
|
||||
Example: `<a href="http://angularjs.org/">link</a>`
|
||||
- Links starting with '/' that lead to a different base path when base is defined<br>
|
||||
Example: `<a href="/not-my-base/link">link</a>`
|
||||
|
||||
|
||||
When running Angular in the root of a domain, along side perhaps a normal application in the same
|
||||
directory, the "otherwise" route handler will try to handle all the URLs, including ones that map
|
||||
to static files.
|
||||
@@ -1,106 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Creating Services
|
||||
@description
|
||||
|
||||
While Angular offers several useful services, for any nontrivial application you'll find it useful
|
||||
to write your own custom services. To do this you begin by registering a service factory function
|
||||
with a module either via the {@link angular.module Module#factory api} or directly
|
||||
via the {@link auto.$provide $provide} api inside of module config function.
|
||||
|
||||
All Angular services participate in {@link di dependency injection (DI)} by registering
|
||||
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
|
||||
dependencies which need to be provided for the factory function of the registered service. The
|
||||
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
||||
testable.
|
||||
|
||||
|
||||
# Registering Services
|
||||
|
||||
To register a service, you must have a module that this service will be part of. Afterwards, you
|
||||
can register the service with the module either via the {@link angular.Module Module api} or
|
||||
by using the {@link auto.$provide $provide} service in the module configuration
|
||||
function. The following pseudo-code shows both approaches:
|
||||
|
||||
Using the angular.Module api:
|
||||
|
||||
```js
|
||||
var myModule = angular.module('myModule', []);
|
||||
myModule.factory('serviceId', function() {
|
||||
var shinyNewServiceInstance;
|
||||
//factory function body that constructs shinyNewServiceInstance
|
||||
return shinyNewServiceInstance;
|
||||
});
|
||||
```
|
||||
|
||||
Using the $provide service:
|
||||
|
||||
```js
|
||||
angular.module('myModule', [], function($provide) {
|
||||
$provide.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 not only be depended upon, but can also have their own dependencies. These can be specified
|
||||
as arguments of the factory function. {@link di Read more} about dependency injection (DI)
|
||||
in Angular and the use of array notation and the $inject property to make DI annotation
|
||||
minification-proof.
|
||||
|
||||
Following is an example of a very simple service. This service depends on the `$window` service
|
||||
(which is passed as a parameter to the factory function) and is just a function. The service simply
|
||||
stores all notifications; after the third one, the service displays all of the notifications by
|
||||
window alert.
|
||||
|
||||
```js
|
||||
angular.module('myModule', [], function($provide) {
|
||||
$provide.factory('notify', ['$window', function(win) {
|
||||
var msgs = [];
|
||||
return function(msg) {
|
||||
msgs.push(msg);
|
||||
if (msgs.length == 3) {
|
||||
win.alert(msgs.join("\n"));
|
||||
msgs = [];
|
||||
}
|
||||
};
|
||||
}]);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
# Instantiating Angular Services
|
||||
|
||||
All services in Angular are instantiated lazily. This means that a service will be created
|
||||
only when it is needed for instantiation of a service or an application component that depends on it.
|
||||
In other words, Angular won't instantiate services unless they are requested directly or
|
||||
indirectly by the application.
|
||||
|
||||
|
||||
# Services as singletons
|
||||
|
||||
Lastly, it is important to realize that all Angular services are application singletons. This means
|
||||
that there is only one instance of a given service per injector. Since Angular is lethally allergic
|
||||
to global state, it is possible to create multiple injectors, each with its own instance of a
|
||||
given service, but that is rarely needed, except in tests where this property is crucially
|
||||
important.
|
||||
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ng Angular Service API}
|
||||
@@ -1,123 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Injecting Services Into Controllers
|
||||
@description
|
||||
|
||||
Using services as dependencies for controllers is very similar to using services as dependencies
|
||||
for another service.
|
||||
|
||||
Since JavaScript is a dynamic language, DI can't figure out which services to inject by static
|
||||
types (like in static typed languages). Therefore, you can specify the service name by using the
|
||||
`$inject` property, which is an array containing strings with names of services to be injected.
|
||||
The name must match the corresponding service ID registered with angular. The order of the service
|
||||
IDs matters: the order of the services in the array will be used when calling the factory function
|
||||
with injected parameters. The names of parameters in factory function don't matter, but by
|
||||
convention they match the service IDs, which has added benefits discussed below.
|
||||
|
||||
```js
|
||||
function myController($loc, $log) {
|
||||
this.firstMethod = function() {
|
||||
// use $location service
|
||||
$loc.setHash();
|
||||
};
|
||||
this.secondMethod = function() {
|
||||
// use $log service
|
||||
$log.info('...');
|
||||
};
|
||||
}
|
||||
// which services to inject ?
|
||||
myController.$inject = ['$location', '$log'];
|
||||
```
|
||||
|
||||
<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', []).
|
||||
factory('notify', ['$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.callNotify = function(msg) {
|
||||
notifyService(msg);
|
||||
};
|
||||
}
|
||||
|
||||
myController.$inject = ['$scope','notify'];
|
||||
</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>
|
||||
|
||||
## Implicit Dependency Injection
|
||||
|
||||
A new feature of Angular DI allows it to 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 = [];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function myController($scope, notify) {
|
||||
$scope.callNotify = function(msg) {
|
||||
notify(msg);
|
||||
};
|
||||
}
|
||||
</file>
|
||||
</example>
|
||||
|
||||
However, if you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming)) your
|
||||
code, your variable names will get renamed in which case you will still need to explicitly specify
|
||||
dependencies with the `$inject` property.
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
## Related APIs
|
||||
|
||||
* {@link ng Angular Service API}
|
||||
@@ -1,113 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Managing Service Dependencies
|
||||
@description
|
||||
|
||||
Angular allows services to declare other services as dependencies needed for construction of their
|
||||
instances.
|
||||
|
||||
To declare dependencies, you specify them in the factory function signature and annotate the
|
||||
function with the inject annotations either using by setting the `$inject` property, as an array of
|
||||
string identifiers or using the array notation. Optionally the `$inject` property declaration can be
|
||||
dropped (see "Inferring `$inject`" but note that that is currently an experimental feature).
|
||||
|
||||
Using the array notation:
|
||||
|
||||
```js
|
||||
function myModuleCfgFn($provide) {
|
||||
$provide.factory('myService', ['dep1', 'dep2', function(dep1, dep2) {}]);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Using the $inject property:
|
||||
|
||||
```js
|
||||
function myModuleCfgFn($provide) {
|
||||
var myServiceFactory = function(dep1, dep2) {};
|
||||
myServiceFactory.$inject = ['dep1', 'dep2'];
|
||||
$provide.factory('myService', myServiceFactory);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Using DI inference (incompatible with minifiers):
|
||||
|
||||
```js
|
||||
function myModuleCfgFn($provide) {
|
||||
$provide.factory('myService', function(dep1, dep2) {});
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Here is an example of two services, one of which depends on the other and both
|
||||
of which depend on other services that are provided by the Angular framework:
|
||||
|
||||
```js
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
function batchLogModule($provide){
|
||||
$provide.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.
|
||||
*/
|
||||
$provide.factory('routeTemplateMonitor',
|
||||
['$route', 'batchLog', '$rootScope',
|
||||
function($route, batchLog, $rootScope) {
|
||||
$rootScope.$on('$routeChangeSuccess', function() {
|
||||
batchLog($route.current ? $route.current.template : null);
|
||||
});
|
||||
}]);
|
||||
}
|
||||
|
||||
// get the main service to kick off the application
|
||||
angular.injector([batchLogModule]).get('routeTemplateMonitor');
|
||||
```
|
||||
|
||||
Things to notice in this example:
|
||||
|
||||
* The `batchLog` service depends on the built-in {@link ng.$interval $interval} and
|
||||
{@link ng.$log $log} services, and allows messages to be logged into the
|
||||
`console.log` in batches.
|
||||
* The `routeTemplateMonitor` service depends on the built-in {@link ngRoute.$route
|
||||
$route} service as well as our custom `batchLog` service.
|
||||
* Both of our services use the factory function signature and array notation for inject annotations
|
||||
to declare their dependencies. It is important that the order of the string identifiers in the array
|
||||
is the same as the order of argument names in the signature of the factory function. Unless the
|
||||
dependencies are inferred from the function signature, it is this array with IDs and their order
|
||||
that the injector uses to determine which services and in which order to inject.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ./ng Angular Service API}
|
||||
* {@link angular.injector Angular Injector API}
|
||||
@@ -1,20 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services
|
||||
@description
|
||||
|
||||
Services are a feature that Angular brings to client-side web apps from the server side, where
|
||||
services have been commonly used for a long time. Services in Angular apps are substitutable
|
||||
objects that are wired together using {@link di dependency injection (DI)}.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers}
|
||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ./ng Angular Service API}
|
||||
@@ -1,62 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Testing Angular Services
|
||||
@description
|
||||
|
||||
The following is a unit test for the 'notify' service in the 'Dependencies' example in {@link
|
||||
dev_guide.services.creating_services Creating Angular Services}. The unit test example uses 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 dev_guide.services.understanding_services Understanding Angular Services}
|
||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ./ng Angular Service API}
|
||||
@@ -1,60 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Angular Services: Understanding Angular Services
|
||||
@description
|
||||
|
||||
## What are Angular Services?
|
||||
|
||||
Angular services are singletons objects or functions that carry out specific tasks common to web apps.
|
||||
Angular has a number of built in services, such as the {@link ng.$http $http service}, which
|
||||
provides access to the browser's `XMLHttpRequest` object for making requests to a server. Like other core
|
||||
Angular variables and identifiers, the built-in services always start with `$` (such as `$http` mentioned
|
||||
above). You can also create your own custom services.
|
||||
|
||||
## Using a Service
|
||||
|
||||
To use an Angular service, you identify it as a dependency for the component (controller, service,
|
||||
filter or directive) that depends on the service. Angular's dependency injection subsystem takes
|
||||
care of the rest. The Angular injector subsystem is in charge of service instantiation, resolution
|
||||
of dependencies, and provision of dependencies to components as requested.
|
||||
|
||||
Angular injects dependencies using
|
||||
["constructor" injection](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/).
|
||||
The dependency is passed to the component's factory/constructor function. Because JavaScript is a dynamically
|
||||
typed language, Angular's dependency injection subsystem cannot use static types to identify service
|
||||
dependencies. For this reason a component must, explicitly, define its dependencies by using one of the
|
||||
{@link di injection annotation} methods. For example, by providing a `$inject` property:
|
||||
|
||||
var MyController = function($location) { ... };
|
||||
MyController.$inject = ['$location'];
|
||||
myModule.controller('MyController', MyController);
|
||||
|
||||
Or by providing an "inline" injection annotation:
|
||||
|
||||
var myService = function($http) { ... };
|
||||
myModule.factory('myService', ['$http', myService]);
|
||||
|
||||
## Defining a Service
|
||||
|
||||
Application developers are free to define their own services by registering their name, and **service
|
||||
factory function**, in Angular modules.
|
||||
|
||||
The purpose of the **service factory function** is to generate the single object, or function, that
|
||||
represents the service to the rest of the application. That object, or function, will then be
|
||||
injected into any component (controller, service, filter or directive) that specifies a dependency
|
||||
on the service.
|
||||
|
||||
Angular factory functions are executed lazily. That is, they are only executed when needed
|
||||
to satisfy a dependency, and are then executed exactly once for each service. Everything that is
|
||||
dependent on this service gets a reference to the single instance generated by the service factory.
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link guide/di About Angular Dependency Injection}
|
||||
* {@link guide/dev_guide.services.creating_services Creating Angular Services}
|
||||
* {@link guide/dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||
* {@link guide/dev_guide.services.testing_services Testing Angular Services}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link ./ng Angular Service API}
|
||||
* {@link angular.injector Injector API}
|
||||
297
docs/content/guide/services.ngdoc
Normal file
297
docs/content/guide/services.ngdoc
Normal file
@@ -0,0 +1,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 is 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 `$`
|
||||
(i.e. `$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-error">
|
||||
**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 and array notation to declare their dependencies.
|
||||
* That 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 is 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}
|
||||
Reference in New Issue
Block a user