aboutsummaryrefslogtreecommitdiffstats
path: root/docs/content/guide/services.ngdoc
diff options
context:
space:
mode:
authorBrian Ford2014-03-03 12:30:33 -0800
committerBrian Ford2014-03-03 12:30:33 -0800
commit220e7bf2d448fd80d98d5c2f3cfac3902433df8f (patch)
tree9b46c834e26a813705a6c39a418f7cef51f6e45b /docs/content/guide/services.ngdoc
parent8d6eed21d219e459331a9f08fd46f8c67a9553da (diff)
downloadangular.js-220e7bf2d448fd80d98d5c2f3cfac3902433df8f.tar.bz2
docs(guide/services): rewrite services documentation
Diffstat (limited to 'docs/content/guide/services.ngdoc')
-rw-r--r--docs/content/guide/services.ngdoc297
1 files changed, 297 insertions, 0 deletions
diff --git a/docs/content/guide/services.ngdoc b/docs/content/guide/services.ngdoc
new file mode 100644
index 00000000..d92be142
--- /dev/null
+++ b/docs/content/guide/services.ngdoc
@@ -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}