Skip to content
Thomas David Kehoe edited this page Jul 13, 2017 · 23 revisions

Services are typically said to be a good idea because they modularize your code. But there's a more important reason to use services. $scope shares data between controllers and templates. It doesn't share data between controllers. To share data between controllers you use a service. If you're having issues with child scopes and parent scopes, maybe you should be using a service.

Angular has five types of services:

  • Value and Constant returns a value. They always return the same value.
  • A factory receives a value, runs a function using the value, and returns a new value.
  • A service creates a new function (using the new keyword). This is useful for object-oriented programming (OOP).
  • Providers do the same things as the above services but with more verbose syntax, enabling more control, including using .config.

Provider Checklist

  1. Make a file for the service, starting with app.value();, app.factory(); etc.
  2. Name the service, e.g., app.value('message');.
  3. Save the file in the services directory. Name it with myValue.js, myFactory.js, etc.
  4. Link from index.html to the service, e.g.,
<script type="text/javascript" src="javascript/services/myValue.js"></script>
<script type="text/javascript" src="javascript/services/myFactory.js"></script>
  1. Inject the service as a dependency into the controller, either

You inject the value as a dependency thus, and then call it:

app.controller("myController", ["$scope", "myValue", function ($scope, myValue) {
...
}];

Listing the dependency twice is done in case you intend to minimize your code. If you don't intend to minimize your code, save time and complexity:

app.controller("myController", function ($scope, myValue) {
...
};
  1. Now you can write your service.

Value and Constant

The service is the second parameter. For a value it's just the value:

app.value("myValue", 9001);
app.value("myValue", "Hello world!");

myValue is the name of the value. 9001 or Hello world! is the value.

To call the value from the controller, use the name of the service:

$scope.powerValue = myValue;

The value can be an object:

app.value("myObject", {
   animal: cat,
   food: mice.
   sound: purr
}
);

Then you can call properties:

$scope.myAnimal = myObject.animal;

The difference between values and constants has to do with configurations and decorators.

Factory

Factories are like values except that the second parameter is a function. The factory syntax is:

app.factory('myFactory', function() {
...
});

You can inject dependencies:

app.factory('myFactory', function(dependency, anotherDependency) {
...
});

No $scope in factories

But you can't inject $scope into services. The purpose of a service is to pass data between controllers, and each controller has its own $scope. Services have to be outside of all the scopes. Instead you use return to pass data out of a service.

You can pass data into a factory through dependencies.

Passing data in and out of factories

Our user story is that the user clicks a button in the view, which passes a value to the controller, which passes the value to a factory, which returns the value to the controller. We'll add logic to the factory later.

<button type="button" ng-click="some('ting')">Ting!</button>
app.factory('myFactory', function() {
   console.log("My factory!") // logs early, when controller loads

   let myData = null;

   let fromController = function(data) { // 'ting' comes from first controller here
      myData = data; // 'ting' transfers to the local variable
      console.log(data); // ting, when user clicks button
   };

   let toController = function() {
      return myData; // returns the local variable, which is now 'ting'
   };

   return { // this entire object is returned if the controller calls myFactory()
      fromController: fromController, // this executes fromController and gets the data
      toController: toController // this returns just the data if the controller uses dot notation to call myFactory.toController()
   }

});
app.controller('MyController', function(sharingFactory) {
   $scope.some = function(data) {
      console.log(data); // ting
      myFactory.fromController(data); // sends data to the factory, this could be a first controller
      let ting = myFactory.toController(); // returns data from the factory, this could be a second controller; remember parentheses to execute the function
      console.log(ting); // ting
   }
};

The matching key: value pairs in the return enable you to call the functions in the factory from the controller. The keys are what you call in the controller, the values are the names of the functions in the factory,

Call your factory

Angular factories use "lazy instantiation." That means that a factory executes when it's injected as a dependency, not when it's called. This is why the console.log executes when the factory loads as a dependency. Calling the factory makes your data pass through and return data:

app.factory("myFactory", function() {
  console.log("Factory injected!");

  return {
    executeMyFactory: function() {
      console.log("Factory executed!");
    }
  }

});

In the controller you then call the object:

console.log("This is just before the factory is called.")
authorizedUserFactory.queryGetRecord(); // call factory
console.log("This is just after the factory is called.")

You should then see:

This is just before the factory is called.
Factory called!
This is just after the factory is called.

Service

A service can pass data between controllers.

Provider

Constant

Clone this wiki locally