Google Groups

Re: What is the difference between module.factory and module.service and how might both be applied?


Miško Hevery Aug 18, 2012 9:38 PM
Posted in group: AngularJS
Lets look at the simplest scenario

provide.value('a', 123);

function Controller(a) {
  expect(a).toEqual(123);
}

in this case the injector simple returns the value as is. But what if you want to compute the value. Then use a factory

provide.factory('b', function(a) {
  return a*2;
});

function Controller(b) {
  expect(a).toEqual(246);
}

So factory is a function which is responsible for creating the value. Notice that the factory function can ask for other dependencies. But what if you want to be more OO and have a class called Greeter

function Greeter(a) {
  this.greet = function() {
    return 'Hello ' + a;
  }
}

then to instantiate you would have to write

provide.factory('greeter', function(a) {
  return new Greeter(a);
});

Then we could ask for 'greeter' in controller like this

function Controller(greeter) {
  expect(greeter instanceof Greeter).toBe(true);
  expect(greeter.greet()).toEqual('Hello 123');
}


But that is way too wordy a shorter way to write this would be
provider.service('greeter', Greeter);

But what it we wanted to configure the Greeter class before the injection then we could write

provide.provider('greeter2', function() {
  var salutation = 'Hello';
  this.setSalutation = function(s) {
    salutation = s;
  }

  function Greeter(a) {
    this.greet = function() {
      return salutation + ' ' + a;
    }
  }

  this.$get = function(a) {
    return new Greeter(a);
  };
});

we can then do this

angular.module('abc', []).configure(function(greeter2Provider) {
  greeter2Provider.setSalutation('Halo');
});

function Controller(greeter2) {
  expect(greeter.greet()).toEqual('Halo 123');
}

But it turns out that angular only understands provide.provider, all other ones are derived.

provider.service = function(name, Class) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.instantiate(Class);
    };
  });
}

provider.factory = function(name, factory) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.invoke(factory);
    };
  });
}

provider.value = function(name, value) {
  provider.factory(name, function() {
    return value;
  });
};


On Thursday, April 19, 2012 3:02:21 PM UTC-7, ProLoser wrote:
On IRC, a few other individuals and I have been a bit confuzzled by how to properly apply these two items in our code.

I believe the main issue is that NO ONE really understands the fundamental difference and purpose.

After reading the docs, I found them to be both circular in definition (EXAMPLE - quickly: having the attribute of being quick) and more importantly, use an almost convoluted degree of industry terminology. Now I don't consider myself an amateur and get most of these fundamental concepts and patterns, but the underlying issue is I have no bloody idea how they are intended to be used and how to apply them.

What I think would help the most is this: Please give a real-world use-case and (more importantly) an analogy to real-world objects so that people trying to learn Angular can understand.

By analogy I mean take the concept of patterns and code completely out of the equation. EXAMPLE:
Abstract class is like the word 'shape'. You can't simply use a shape, you need to specify exactly what kind of shape you are making in order to understand how it will behave. Extending an abstract class is like how a 'square' falls under the classification of 'shape' but you can specify dimension of a square and how it will behave, such as rolling. You CAN however determine general information, such as how many shapes are on the piece of paper, or that every shape can have a color.

Sorry I realize that's long, but I really think this is a very lacking and a lot of people have been asking these very questions.