Friday, April 29, 2016

Difference Between Value, Factory, and Service in AngularJs

There are various ways to create Objects in JavaScript. A couple include:

Using Object literal notation: Reference

var carObj = {
  model: "Mercedes-Benz CLS Coupé",
  getModel: function() {
  return this.model;
  }
}

console.log(carObj.getModel()); // prints Mercedes-Benz CLS Coupé


Using Constructor function: Reference

var BenzObj = function() {
  this.model = "Mercedes-Benz CLS Coupé",
  this.getModel = function () {return this.model}
};

var carObj = new BenzObj();

console.log(carObj.getModel()); // prints Mercedes-Benz CLS Coupé

I once wrote about the Constructor function. Check the post: Understanding Constructor Function and this Keyword in Javascript

Using the Module Pattern: Reference

This is a method that combines Javascript's Immediately-invoked function expression, and Object literal notation to provide a way to make objects:

var carObj = (
// function that is immediately invoked
function() {
 return {
    model: "Mercedes-Benz CLS Coupé",
    getModel: function() {
    return this.model;
   }
 }
})()

console.log(carObj.getModel()); // prints Mercedes-Benz CLS Coupé

Value,  Service and Factory mechanism in AngularJs are just 3 different ways of object creation that maps to these 3 ways of object creation in vanilla JavaScript...

Basically...

AngularJs’s Value maps to using Object literal to create objects
Angular’s Service maps to using Constructor function to create objects
Angular’s Factory maps to using the Module pattern (or a factory function) to create objects.

And there you have the difference between Value, Service and Factory methods in AngularJs.

Let us now go ahead and see how this looks in practice.

Value

angular.module('carsModule').value("carObj", {
  model: "Mercedes-Benz CLS Coupé",
  getModel: function() {
  return this.model;
  }
});

So we are telling AngularJs that an Object we create using object literal notation should be registered as "carObj". In other parts of the application, we can then ask for it by referring to "carObj".

angular.module('carsModule', [])
 // We register carObj with angular using value...
 .value("carObj", {
  model: "Mercedes-Benz CLS Coupé",
  getModel: function() {
  return this.model;
  }
})
 .controller("Cars_Controller", ["carObj", function(car) {
  // ...and then carObj is made available in the Cars_Controller
  console.log(car);
 }])

Service


Our constructor function:

var BenzObj = function() {
  this.model = "Mercedes-Benz CLS Coupé",
  this.getModel = function () {return this.model}
};
but we do not use 'new' on it directly, we register it with AngularJs using service, and then it is made available in the controller
angular.module('carsModule', [])
 .service("carObj", BenzObj)
 .controller("Cars_Controller", ["carObj", function(car) {
  // ...and then carObj is made available in the Cars_Controller
  console.log(car);
 }])


We could have also passed in the function directly instead of first assigning it to BenzObj

angular.module('carsModule', [])
  // registers the constructor function
 .service("carObj", function() {
  this.model = "Mercedes-Benz CLS Coupé",
  this.getModel = function () {return this.model}
 })
 .controller("Cars_Controller", ["carObj", function(car) {
 // Angular Injects the carObj by 
 // calling new on the constructor function passed in
  console.log(car);
 }])

Irrespective of whether we pass the function directly in or not, what is going on remains the same. We have a constructor function that is registered using Service. AngularJs considers the function registered as a Constructor function and thus when we refer to it in other part of the application, AngularJs calls new on the function and returns the object created.

Factory


We have our function:

var benzObjFactory = function() {
 return {
    model: "Mercedes-Benz CLS Coupé",
    getModel: function() {
    return this.model;
   }
 }
}

Notice that the function is not wrapped inside an immediately invoked function expression? AngularJs would do that for us; that is, AngularJs will invoke it for us.

We then register this function with AngularJs as a Factory:

angular.module('carsModule', [])
  // registers the constructor function
 .factory("carObj", benzObjFactory);

Or we could have registered the function with AngularJs directly just as was shown with the Service demonstration.

We can then ask for the object created by the function, in other part of the application (i.e. in the controller) by referring to it using the name we registered it with:

angular.module('carsModule', [])
  // registers the factory function
 .factory("carObj", benzObjFactory)
 .controller("Cars_Controller", ["carObj", function(car) {
 // Angular Injects the carObj by calling the benzObjFactory
  console.log(car);
 }])

So even though Value, Service, Factory might sound like fancy terms, they are not that complicated, once you realise they are just AngularJs ways of creating objects which maps to ways of doing the same in vanilla JavaScript.

I am writing a book: TypeScript Beyond The Basics. Sign up here to be notified when it is ready.

No comments: