Intended Audience

Anyone trying to get services working for the first time in Angular, or if you are having trouble with dependency injection.

Or perhaps you are encountering helpful errors such as:

Error: [$injector:unpr] Unknown provider:

(Service module not injected into the controller)

ReferenceError: serviceName is not defined

(Service referenced in code but not injected into the controller or added to the controller function call)

TypeError: Cannot call method 'sayHello' of undefined

(Service method referenced in code and has been added to the controller function but the service has not been properly injected into the controller)

Intro

After reviewing the Angular Tutorial and starting work on my first Angular app, I am getting tripped up by Services.

There are a lot of posts out there about Angular Services, including some ok documentation at Angular site,  but I’m still having a hard time just getting off the ground when registering my own services. This post aims to get first timers up and running with a basic understanding of how to create and use Angular Services.

There are several ways to register services, and many different syntaxes for registering them in the services.js, which makes it really difficult to look at 10 different posts and connect all the dots. This is my attempt to connect some of the dots in a single post/repo.

Repository

A copy of the Angular Seed project:

https://github.com/godoloju/Getting-Started-with-Angular-Services

Branches

There are links to relevant files in specific branches throughout the document.

Working Demo

Using rawgithub there are links to the Angular application within the repository that allow you to see the application in action.

The Basics

There is a pretty good [1,000 foot] overview of this on the Angular Tutorial 11 – REST and Custom Services, I’m going to cover the same basic steps, but from a different perspective.

There are some basic concepts that were lost on me after going through the Angular Tutorial. The following terms/concepts are very important to have a good handle on.

Module

What is a module? A module is an Angular JavaScript Object. Modules organize code within Angular. They are the building blocks of Angular, they are referenced by name for dependency injection (which is how the application is boot-strapped). Every time you see ` angular.module( ‘moduleName’ ` know that a new module named moduleName is being declared. A module is a collection of code which can be referenced (injected) by the given module name.

The Module API shows all of the methods available – there is a long list, but it was helpful for me to look over the methods and make the connection to the module methods which allow for adding directives, services, filters, controllers… modules are at the heart of everything. If you take a look through all of the /app/js files in the Angular Seed, you will see that modules are the building blocks glued together as needed by dependency injection.

  • Modules depend on other Modules.
  • Modules are available from JavaScript includes on the index page (or partials?)
  • You can inject any available Module on any other Module (you don’t have to expose a module to parent modules).
  • There is no inheritance when it comes to module dependency, modules must be injected right where they are needed.

Service

While you can create the logic that you need for a web application right in the Controller (app/js/controllers.js), you can better organize the code & make it reusable, by putting it in a Module, one of the ways of adding code to a module is as a service. A service is appropriate when a singleton is needed.

Dependency Injection

This is really where things got wonky for me. Figuring out where and how to declare the module dependency and service took me many hours of trial and error.  For a module.service used within a controller, it comes down to declaring the module dependency, the service dependency, and adding the service to the controller function to make it available.

To use a service in a controller:

  1. Declare Module Dependency
  2. Declare Service Dependency
  3. Declare Service in Controller Function
  4. Call the Service by name in the controller

Creating a Service

There are 4 different ways to generate services based on the angular.module API.

  1. value
  2. service
  3. factory
  4. provider

There is a section for each type listed below with ALL of the relevant code included for implementing that type of service.

-FEAST ON-

Value Service

Syntax: value(‘serviceName’, object);

Result: When declaring serviceName as an injectable argument you will be provided with a value. (Technically a value service).

Define a simple service:

Let’s say that we have the service ‘testService’ in the module ‘asdf‘ declared:

/app/js/services.js

//Services Module
var app = angular.module('asdf', []);
// Service definition
app.value('testService', "Hello value service");

 1) Declare Module Dependency

In order to use the ‘testService‘ in a controller, you need to declare the dependency between the controller module (‘myApp.controllers‘) and the service module (‘asdf‘). This is done by adding the service module name (‘asdf‘) to the controller module declaration. This makes the service available to use in the controller declarations.

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', [function() {

  }])
  .controller('MyCtrl2', [function() {

  }])

2) Declare Service Dependency

And in the controller declaration, the controller ‘MyCtrl1‘ depends on ‘testService

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function() {

  }]).
  controller('MyCtrl2', [function() {

  }]);

3) Declare Service in Controller Function

And in the controller declaration, the controller ‘MyCtrl1‘ depends on ‘moduleName

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function(testService) {

  }]).
  controller('MyCtrl2', [function() {

  }]);

4) Call the Service by name in the controller

And now we can call the testService function sayHello in the controller

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function(testService) {
    console.dir(testService);
  }]).
  controller('MyCtrl2', [function() {

  }]);

Relevant files from the ‘2-Value-Service’ branch

https://github.com/godoloju/Getting-Started-with-Angular-Services/tree/2-Value-Service

/app/js/controllers.js

/app/js/services.js

See this exciting service in action (on the console) via rawgithub.

Service Service

Syntax: module.service( ‘serviceName’, function );

Result: When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassedToService().

Let’s say that we have the service ‘testService’ in the module ‘asdf‘ declared:

/app/js/services.js

//Services Module
var app = angular.module('asdf', []);
// Service definition
app.service('testService', function(){
    this.sayHello= function(text){
        return "Service says \"Hello " + text + "\"";
    };        
});

 1) Declare Module Dependency

In order to use the ‘testService‘ in a controller, you need to declare the dependency between the controller module (‘myApp.controllers‘) and the service module (‘asdf‘). This is done by adding the service module name (‘asdf‘) to the controller module declaration. This makes the service available to use in the controller declarations.

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', [function() {

  }])
  .controller('MyCtrl2', [function() {

  }])

2) Declare Service Dependency

And in the controller declaration, the controller ‘MyCtrl1‘ depends on ‘testService

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function() {

  }]).
  controller('MyCtrl2', [function() {

  }]);

3) Declare Service in Controller Function

And in the controller declaration, the controller ‘MyCtrl1‘ depends on ‘moduleName

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function(testService) {

  }]).
  controller('MyCtrl2', [function() {

  }]);

4) Call the Service by name in the controller

And now we can call the testService function sayHello in the controller

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function(testService) {
    console.dir(testService.sayHello("World"));
  }]).
  controller('MyCtrl2', [function() {

  }]);

Relevant files from the ‘1-Dependency-Injection’ branch

https://github.com/godoloju/Getting-Started-with-Angular-Services/tree/1-Dependency-Injection

/app/js/controllers.js

/app/js/services.js

See this exciting service in action (on the console) via rawgithub.

Factory Service

Syntax: module.factory( ‘factoryName’, function );

Result: When declaring factoryName as an injectable argument you will be provided with the value that is returned by invoking the function reference passed to module.factory.

Syntax: module.service( ‘serviceName’, function );

Result: When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassedToService().

Let’s say that we have the service ‘testService’ in the module ‘asdf‘ declared:

/app/js/services.js

//Services Module
var app = angular.module('asdf', []);
// Service definition
app.factory('testService', function(){
    return {
    	sayHello : function(text){
        	return "Factory Object says \"Hello " + text + "\"";
    	}
    };
});

 1) Declare Module Dependency

In order to use the ‘testService‘ in a controller, you need to declare the dependency between the controller module (‘myApp.controllers‘) and the service module (‘asdf‘). This is done by adding the service module name (‘asdf‘) to the controller module declaration. This makes the service available to use in the controller declarations.

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', [function() {

  }])
  .controller('MyCtrl2', [function() {

  }])

2) Declare Service Dependency

And in the controller declaration, the controller ‘MyCtrl1‘ depends on ‘testService

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function() {

  }]).
  controller('MyCtrl2', [function() {

  }]);

3) Declare Service in Controller Function

And in the controller declaration, the controller ‘MyCtrl1‘ depends on ‘moduleName

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function(testService) {

  }]).
  controller('MyCtrl2', [function() {

  }]);

4) Call the Service by name in the controller

And now we can call the sayHello method from the testService that was passed into the controller

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function(testService) {
    console.dir(testService.sayHello("World"));
  }]).
  controller('MyCtrl2', [function() {

  }]);

Relevant files from the ‘3-Factory-Service’ branch

https://github.com/godoloju/Getting-Started-with-Angular-Services/tree/3-Factory-Service

/app/js/controllers.js

/app/js/services.js

See this exciting service in action (on the console) via rawgithub.

Provider Service

Syntax: module.provider( ‘providerName’, function );

Result: When declaring providerName as an injectable argument you will be provided with ProviderFunction().$get(). The constructor function is instantiated before the $get method is called – ProviderFunction is the function reference passed to module.provider.

Providers have the advantage that they can be configured during the module configuration phase.

Syntax: module.service( ‘serviceName’, function );

Result: When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassedToService().

Let’s say that we have the service ‘testService’ in the module ‘asdf‘ declared:

/app/js/services.js

//Services Module
var app = angular.module('asdf', []);
// Service definition
app.provider('testService', function () {

  var HelloWorldClass = function(t){
  	this.text = t;
    this.sayHello = function () {
      return "Provider Service Object says \"Hello " + this.text + "\"";
    }
  }

  this.$get = function() {
    return HelloWorldClass;
  };
});

 1) Declare Module Dependency

In order to use the ‘testService‘ in a controller, you need to declare the dependency between the controller module (‘myApp.controllers‘) and the service module (‘asdf‘). This is done by adding the service module name (‘asdf‘) to the controller module declaration. This makes the service available to use in the controller declarations.

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', [function() {

  }])
  .controller('MyCtrl2', [function() {

  }])

2) Declare Service Dependency

And in the controller declaration, the controller ‘MyCtrl1‘ depends on ‘testService

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function() {

  }]).
  controller('MyCtrl2', [function() {

  }]);

3) Declare Service in Controller Function

And in the controller declaration, the controller ‘MyCtrl1‘ depends on ‘moduleName

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function(testService) {

  }]).
  controller('MyCtrl2', [function() {

  }]);

4) Call the Service by name in the controller

And now we can call the testService provider to return a HelloWorldClass in the controller and then call sayHello from the HelloWorldClass.

/app/js/controllers.js

angular.module('myApp.controllers', ['asdf']).
  controller('MyCtrl1', ['testService', function(testService) {
    var helloWorld = new testService('Not World');
    console.dir(helloWorld.sayHello());
  }]).
  controller('MyCtrl2', [function() {

  }]);

Relevant files from the ‘4-Provider-Service’ branch

https://github.com/godoloju/Getting-Started-with-Angular-Services/tree/4-Provider-Service

/app/js/controllers.js

/app/js/services.js

See this exciting service in action (on the console) via rawgithub.

The End

I would like to note that I am a complete noob to Angular – writing a blog post as a noob is a fantastic way to pound in new concepts and maybe, just maybe, help another noob.

Another great post on this subject : http://clevertech.biz/devblog/angularjs-factory-service-provider/

Creating a Service section inspire by a useful post on stackoverflow.com angular-js-service-vs-provider-vs-factory

Leave a reply

Your email address will not be published. Required fields are marked *