| <a href='http://github.com/angular/angular.js/edit/master/docs/content/guide/services.ngdoc' class='improve-docs btn btn-primary'><i class="glyphicon glyphicon-edit"> </i>Improve this doc</a> |
| |
| |
| <h1 id="services">Services</h1> |
| <p>Angular services are substitutable objects that are wired together using <a href="guide/di">dependency</a> |
| injection (DI). You can use services to organize and share code across your app.</p> |
| <p>Angular services are:</p> |
| <ul> |
| <li>Lazily instantiated – Angular only instantiates a service when an application component depends |
| on it.</li> |
| <li>Singletons – Each component dependent on a service gets a reference to the single instance |
| generated by the service factory.</li> |
| </ul> |
| <p>Angular offers several useful services (like <a href="api/ng/service/$http"><code>$http</code></a>), but for most applications |
| you'll also want to <a href="guide/services#creating-services">create your own</a>.</p> |
| <div class="alert alert-info"> |
| <strong>Note:</strong> Like other core Angular identifiers built-in services always start with <code>$</code> |
| (e.g. <code>$http</code>). |
| </div> |
| |
| |
| <h2 id="using-a-service">Using a Service</h2> |
| <p>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 <a href="guide/di">dependency injection</a> |
| subsystem takes care of the rest.</p> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-example108@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-example108" |
| module="myServiceModule"> |
| |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code><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></code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="script.js" |
| language="js" |
| type="js"> |
| <pre><code>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 = []; } }; }]);</code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="protractor.js" |
| type="protractor" |
| language="js"> |
| <pre><code>it('should test service', function() { expect(element(by.id('simple')).element(by.model('message')).getAttribute('value')) .toEqual('test'); });</code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-example108/index.html" name="example-example108"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <div class="alert alert-info"> |
| <strong>Note:</strong> Angular uses |
| <a href="http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/"><strong>constructor injection</strong></a>. |
| </div> |
| |
| <h3 id="explicit-dependency-injection">Explicit Dependency Injection</h3> |
| <p>A component should explicitly define its dependencies using one of the <a href="guide/di">injection</a> |
| annotation methods:</p> |
| <ol> |
| <li><p>Inline array injection annotation (preferred):</p> |
| <pre><code class="lang-js">myModule.controller('MyController', ['$location', function($location) { ... }]);</code></pre> |
| </li> |
| <li><p><code>$inject</code> property:</p> |
| <pre><code class="lang-js">var MyController = function($location) { ... }; |
| MyController.$inject = ['$location']; |
| myModule.controller('MyController', MyController);</code></pre> |
| </li> |
| </ol> |
| <div class="alert alert-success"> |
| <strong>Best Practice:</strong> Use the array annotation shown above. |
| </div> |
| |
| <h3 id="implicit-dependency-injection">Implicit Dependency Injection</h3> |
| <p>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 <code>$window</code>, <code>$scope</code>, and our <code>notify</code> service:</p> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-example109@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-example109" |
| module="myServiceModuleDI"> |
| |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code><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></code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="script.js" |
| language="js" |
| type="js"> |
| <pre><code>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); }; });</code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-example109/index.html" name="example-example109"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <div class="alert alert-danger"> |
| <strong>Careful:</strong> If you plan to <a href="http://en.wikipedia.org/wiki/Minification_(programming">minify</a> your code, |
| your variable names will get renamed unless you use one of the annotation techniques above. |
| </div> |
| |
| |
| <h2 id="creating-services">Creating Services</h2> |
| <p>Application developers are free to define their own services by registering the service's name and |
| <strong>service factory function</strong>, with an Angular module.</p> |
| <p>The <strong>service factory function</strong> 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.</p> |
| <h3 id="registering-services">Registering Services</h3> |
| <p>Services are registered to modules via the <a href="api/ng/type/angular.Module">Module API</a>. |
| Typically you use the <a href="api/ng/function/angular.module">Module#factory</a> API to register a service:</p> |
| <pre><code class="lang-javascript">var myModule = angular.module('myModule', []); |
| myModule.factory('serviceId', function() { |
| var shinyNewServiceInstance; |
| //factory function body that constructs shinyNewServiceInstance |
| return shinyNewServiceInstance; |
| });</code></pre> |
| <p>Note that you are not registering a <strong>service instance</strong>, but rather a <strong>factory function</strong> that |
| will create this instance when called.</p> |
| <h3 id="dependencies">Dependencies</h3> |
| <p>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.</p> |
| <p>The example module below has two services, each with various dependencies:</p> |
| <pre><code class="lang-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); |
| }); |
| }]);</code></pre> |
| <p>In the example, note that:</p> |
| <ul> |
| <li>The <code>batchLog</code> service depends on the built-in <a href="api/ng/service/$interval"><code>$interval</code></a> and |
| <a href="api/ng/service/$log"><code>$log</code></a> services.</li> |
| <li>The <code>routeTemplateMonitor</code> service depends on the built-in <a href="api/ngRoute/service/$route"><code>$route</code></a> |
| service and our custom <code>batchLog</code> service.</li> |
| <li>Both services use the array notation to declare their dependencies.</li> |
| <li>The order of identifiers in the array is the same as the order of argument |
| names in the factory function.</li> |
| </ul> |
| <h3 id="registering-a-service-with-provide-">Registering a Service with <code>$provide</code></h3> |
| <p>You can also register services via the <a href="api/auto/object/$provide"><code>$provide</code></a> service inside of a |
| module's <code>config</code> function:</p> |
| <pre><code class="lang-javascript">angular.module('myModule', []).config(function($provide) { |
| $provide.factory('serviceId', function() { |
| var shinyNewServiceInstance; |
| //factory function body that constructs shinyNewServiceInstance |
| return shinyNewServiceInstance; |
| }); |
| });</code></pre> |
| <p>This technique is often used in unit tests to mock out a service's dependencies.</p> |
| <h2 id="unit-testing">Unit Testing</h2> |
| <p>The following is a unit test for the <code>notify</code> service from the <a href="guide/services#creating-services">Creating Angular Services</a> example above. The unit test example uses a Jasmine spy (mock) instead |
| of a real browser alert.</p> |
| <pre><code class="lang-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"]); |
| });</code></pre> |
| <h2 id="related-topics">Related Topics</h2> |
| <ul> |
| <li><a href="guide/di">Dependency Injection in AngularJS</a></li> |
| </ul> |
| <h2 id="related-api">Related API</h2> |
| <ul> |
| <li><a href="./ng">Angular Service API</a></li> |
| <li><a href="api/ng/function/angular.injector">Injector API</a></li> |
| </ul> |
| |
| |