Can service and factory be used interchangeably? - angularjs

Angular JS conceptual overview. View-independent business logic: Services (heading).
The description says - moving view-independent logic from the controller into a service, yet the code says factory. What am I missing here?
angular.module('finance2', [])
.factory('currencyConverter', function() {
var currencies = ['USD', 'EUR', 'CNY'];
Link to the resource

The factory method ('recipe') is a way of creating a 'Service'.
You can also create 'Services' with the service, constant, value, and provider recipes ('methods').
However you do it, you'll end up instantiating an object that is conceptually a 'Service'.
It's been acknowledged widely that this is a confusing aspect of Angular. See this classic Stackoverlow question.
The developer guide does a good job of clarifying these concepts too:
Each web application you build is composed of objects that collaborate to get stuff done. These objects need to be instantiated and wired together for the app to work. In Angular apps most of these objects are instantiated and wired together automatically by the injector service.
The injector creates two types of objects, services and specialized objects.
Services are objects whose API is defined by the developer writing the service.
Specialized objects conform to a specific Angular framework API. These objects are one of controllers, directives, filters or animations.
The injector needs to know how to create these objects. You tell it by registering a "recipe" for creating your object with the injector. There are five recipe types.
The most verbose, but also the most comprehensive one is a Provider recipe. The remaining four recipe types — Value, Factory, Service and Constant — are just syntactic sugar on top of a provider recipe.

Coming from a Java background, I really like the concept of angular factories; we get to mimic POJOs here to an extent. I get to attach meaningful methods and execute logic that's all self-contained within the model itself. Whereas for services, I tend to treat those as I'd treat a service on the server-side, simply for fetching data.
For instance, if we were building a Twitter clone of some sort, for the tweet stream, I'd have a TweetSteamFactory that internally fetches data using TweetService to get the latest tweets. Maybe my factory has a getNextPage() method, which is bound to an ngClick somewhere - when fired, it of course makes its call with TweetService.
At any rate, I do see a pretty clear distinction between services and factories, although my understanding could be misguided.
http://plnkr.co/edit/SqPf212nE5GrSPcZdo5K
Controller
app.controller('MyController', function(FoobarFactory) {
FoobarFactory()
done(function(factory) {
var factory = factory;
$scope.data = factory.getData();
$scope.baz = factory.getBaz();
})
});
Factory
app.factory('FoobarFactory', ['MyService', function(MyService) {
function Foobar() {}; // Empty constructor
angular.extend(Foobar.prototype, {
_init: function() {
var deferred = $.Deferred();
var foobar = this;
this.baz = true;
this.data = undefined;
MyService.getData()
.done(function(data) {
foobar.data = data;
deferred.resolve(foobar);
})
deferred.resolve();
return deferred.promise();
},
getBaz: function() {
return this.baz;
},
getData: function() {
return this.data;
}
});
return function () {
var deferred = $.Deferred();
var foobar = new Foobar();
foobar._init()
.done(function() {
deferred.resolve(foobar);
})
.fail(function(error) {
deferred.reject(error);
});
return deferred.promise();
};
}]);

Related

object is being created twice angular

I am using angular and grafana in my project.
I have a service -> dashboardViewStateSrv
My Service Code :
define([
'angular',
'lodash',
'jquery',
],
function (angular, _, $) {
'use strict';
var module = angular.module('grafana.services');
module.factory('dashboardViewStateSrv', function($location, $timeout) {
function DashboardViewState($scope) {
var self = this;
self.state = {};
self.panelScopes = [];
self.$scope = $scope;
// something
}
return {
create: function($scope) {
return new DashboardViewState($scope);
}
};
});
});
In My side menu controller :
$scope.dashboardViewState = dashboardViewStateSrv.create($scope);
if ($scope.dashboardViewState) {
if($scope.dashboardViewState.state.citreedepth){
depth = +$scope.dashboardViewState.state.citreedepth;
}
}
In My Dashboard controller :
$scope.dashboardViewState = dashboardViewStateSrv.create($scope);
DashboardViewState object is being created twice (Dashboard Ctrl and Side Menu ctrl).
I am creating DashboardViewState object twice, I want to avoid that. If I can avoid creating DashboardViewState object in Side Menu ctrl?
There should be only one view state. As per my understanding all the services are singleton in angular.
Please guide me what I can do?
Services are singletons, they are essentially a constructure function allowing you to use the this keyword inside them. They are instantiated once when first created then that instance is shared throughout your app.
Factories are, well, factories. Somewhere in Angular it will call Object.create() on the object your return from a factory. Meaning each call will return a new instance of it.
So in your use case your creating a new object twice. First by using a factory, then second by returning a new object from that factory.
This may help http://blog.thoughtram.io/angular/2015/07/07/service-vs-factory-once-and-for-all.html
So if you want a single instance of an object through your application you should use .service() not .factory();
If you want to instantiate a new Object only once you could use a service. Have the object as a property and a get method. The service could check if the object is already created and if not make it.
something like this (example code, not tested):
module.service('dashboardViewStateSrv', function($location, $timeout) {
this.object;
this.get = function (){
if(this.object === undefined) {
return this.object = Object.create({}); //Create your object
} else {
return this.object;
}
}
});
however i did notice some booboo's (Sorry always reminds me of Hook when i say that). First you do not need to alias the this keyword, were not working in an jQuery callback, even if we were you can bind your function etc.
Second and this is important. Your passing a $scope object into your service, this is very very bad. Not just for this reason but how can controllers share a single service object if it has a reference to a $scope? Your services should be a collection of single simple methods that have their input and output data. They work on that and continue. You can then chain them and pass them the specific data each method needs. They shouldn't be a monolithic object that has everything in hidden properties, think functional, a pipeline if you will.

AngularJS dependency injection swap implementation

I'm still learning AngularJS, and have a question regarding their flavor of dependency injection. For example purposes, say I have a DataProcessor service which has a processData method that takes in a uri parameter and it needs to read that data (which may be xml, json, etc.) and then perform some actions on it. The DataProcessor constructor takes in an implementation of a DataReader interface that knows how to read a certain file type. Here are some example services of what I'm talking about:
// implementations of the DataReader interface
myApp.service('XmlDataReader', function() {
this.readData = function(uri) {
// read xml data from uri
}
}]);
myApp.service('JsonDataReader', function() {
this.readData = function(uri) {
// read json data from uri
}
}]);
// data processing service that takes in an implementation of a DataReader
myApp.service('DataProcessor', ['DataReader', function(DataReader) {
this.processData = function(uri) {
var readData = DataReader.readData(uri);
// process data and return it
}
}]);
From a typical dependency injection perspective, a specific type of DataReader could be passed into the DataProcessor and used like so:
var dataProcessor = new DataProcessor(new JsonDataReader());
var processedData = dataProcessor.processData('dataz.json');
What is the AngularJS way of doing this?
Do something like this:
myApp.service('DataProcessor', ['$injector', 'valueRecipeOfTheServicename', function($injector, valueRecipeOfTheServicename) {
this.processData = function(uri) {
var service = $injector.get(valueRecipeOfTheServicename);
// process data and return it
}
}]);
$injetcor.get() retrieves a service
Based on Noypi Gilas answer, I am initiating the controller with the name of the service and retrieving it via $injetcor.get():
myApp.service('DataProcessor', ['$injector', function($injector) {
var service;
$scope.init = function (serviceName) {
service = $injector.get(serviceName);
}
this.processData = function(uri) {
// use the service ...
}
}]);
Because of the way DI works - you shouldn't have to create instances of your services, ever really. What you do is you inject the service(s) you need into your controller and it should just work. In the case above, your controller might be defined to be:
var app = angular.module('App', ['DataProcessor']);
function MyController($scope, DataProcessor) {
var uri = '';
DataProcessor.processData(uri);
}
The only other thing you need to do here is make sure that "App" is the name you specify in the "ng-app" directive and make sure that your page includes the JS files with "DataProcessor" before you include the angular app module (technically these could even be defined in the same file). Hope this helps!
Edit
By the way, if you need to minify - the following is how you would define the controller:
var app = angular.module('App', ['DataProcessor']);
// if you need to minify:
var MyController = ['$scope', 'DataProcessor',
function($scope, DataProcessor) {
var uri = '';
DataProcessor.processData(uri);
}
];
Additional Suggestions
My understanding of a service at the present time is that is is used to shared data or code between controllers. If this data processing is specific to that controller you might consider just moving the "ProcessData" implementation directly into your controller. Sometimes changes like this can be simpler than processing the data in a service. If you do process the data in the service you might still want to write that data back to the scope. In this case, you can pass $scope as a parameter into the service routine. Since I don't know too much about your use case, just take these suggestions with a grain of salt. Good luck!

Breezejs, How to fetch metadata at start with shared EntityManager

I have an Angular application using Breeze and that has a shared EntityManager for my different controllers. A few of my controllers can be reached without executing a query to pre-populate the EntityManager's MetadataStore. I have found somewhat of a starting direction here saying to fetch the metadata at the start of the application. My project is based on the Angular-Breezejs template and when i try doing the following I get errors because the promise isn't fully resolved before something uses the datacontext.
app.factory('datacontext',
['breeze', 'Q', 'model', 'logger', '$timeout',
function (breeze, Q, model, logger, $timeout) {
logger.log("creating datacontext");
configureBreeze();
var manager = new breeze.EntityManager("/api/app");
manager.enableSaveQueuing(true);
var datacontext = {
metadataStore: manager.metadataStore,
saveEntity: saveEntity,
getUsers: getUsers,
getUser: getUser,
createUser: createUser,
deleteUser: deleteUser
};
return manager.fetchMetadata()
.then(function () {
model.initialize(datacontext);
return datacontext;
})
.fail(function (error) {
console.log(error);
return error;
});
//Function definitions
What is the proper way of blocking until the metadata fetch is complete? Since it seems unnecessary to have to check if the metadata exists before each non-query function (including entity creation) like the original poster of the linked question above ended up doing.
I see your problem.
When Angular invokes your factory function to create the DataContext service, it expects to get back immediately (synchronously) a DataContext object that is ready to use. But you are returning a promise to return that DataContext at some time in the future ... and Angular just isn't built for that.
I like the idea though. You might want to propose it to the Angular team :-).
So what you're trying here just won't work. You have to return a DataContext immediately. Until the metadata arrive, you have to either block the entire UI or block the specific functionality that relies on metadata (e.g., createUser). It's kind of like waiting for the DOM to settle down before manipulating it with jQuery.
This situation is not Angular specific. You face the same quandary in a Knockout app. The resolution is similar.
Start by exposing some kind of "whenReady" hook on the DataContext. A promise might be a good idea. Something like this:
function (breeze, Q, model, logger, $timeout) {
logger.log("creating datacontext");
...
var readyDeferred = Q.defer(), whenReady = readyDeferred.promise;
var datacontext = {
whenReady: whenReady,
...
};
initializeDatacontext();
return datacontext; // now Angular is happy because it has a datacontext
function initializeDatacontext() {
manager.fetchMetadata()
.then(function () {
readyDeferred.resolve();
// do success stuff;
})
.fail(function (error) {
readyDeferred.reject(error);
// do error stuff;
});
}
//Function definitions
}
Elsewhere in the bootstrapping of your app, you tie into the datacontext.whenReady promise.
// somewhere inside your main controller
$scope.isReady = false;
datacontext.whenReady.then(function() {
$scope.isReady = true;
$scope.$apply();
})
.fail(function() { alert("Uh oh!"); });
...
Now bind the scope's isReady to the HTML such that you get the desired behavior. You could use it to block the entire UI or just seal off functionality (e.g, "Create User") until the datacontext is ready.
Pleae don't use this pseudo-code literally. Use it for inspiration.

Grouping back-end APIs

While using AngularJS's $http service I've found hard to manage all urls to backend - they're spread around controller's code. Sometimes they're even duplicated. Mostly all of them are in form of $http.get('/api/something').then(...).
To put all of them into different services sounds quite unreasonable: it is just one line of code with may be just small modifications (like adding header etc).
Other solution could be putting them into constants, but in this case I would still use $http.get(APIURLs.SomeURL) that looks like little bit verbose...
So the question is: what is the best way to manage URLs to back-end?
Currently I came up with idea of grouping them into servicies and expose them as calls to $http. Here is my solution:
http://plnkr.co/edit/VjqXHBV54bmjKCuGJ4qX?p=preview
Service:
.factory('AdminAPI', function($http) {
var apiMap = {
'DeleteAuth': {url:'/api/oauth/delete',method:'PUT'},
'GetInvalidUser': {url:'/api/users/invalid',method:'GET'},
'CreateItem': {url:'/api/items/create',method:'POST'}
};
var api = {};
var prepareCall = function(config) {
return function(params) {
var requestConfig = angular.copy(config);
if (config.method=='GET')
requestConfig.params = params;
else
requestConfig.data = params;
return $http(requestConfig);
};
};
for(var name in apiMap)
api[name] = prepareCall(apiMap[name]);
return api;
});
And in controllers I do something like:
AdminAPI.DeleteAuth({data:123}).then(function(result) {
//
});
In this case I have some abstraction (do not have to inject $http into controller), so unit-tests become little bit easier (I do not have to use $httpBackend service, just mock my service calls).
Make use of angular Module.constant:
Move reusable settings to single object;
Define angular module wrapping this object:
angular.module('myApp.constants', []).constant('config', {
ROUTES: {
home: '/home.html',
about: '/about.html'
}
});
load myApp.constants module into application with all the others:
angular.module('myApp', [
'myApp.constants',
'myApp.services',
'myApp.controllers',
'myApp.filters',
'myApp.directives'
]);
After that you can inject config dependency and access defined hash.
Good question. My suggested approach is to put the constants in a constantdeclaration like this:
angular.module('fooApp').constant('config', {
api: {
baseUrl: 'http://api.example.com/api',
key: 'SECRET_API_KEY',
}
});
And you could implement a httpResourceFactory that is responsible for creating $http or $resource references that points to different endpoints using the constants defined in config.
This could be implemented in a service.
Then all API endpoint definitions can be put into a single service.
angular.module('fooApp').factory('dataService', ['httpResourceFactory', function(httpResourceFactory) {
var PUBLIC_API = {};
PUBLIC_API.Orders = httpResourceFactory('/orders/:id');
PUBLIC_API.Users = httpResourceFactory('/some-url/users/:id');
return PUBLIC_API;
}]);
Then in your controller you may inject dataService and do stuff like this:
$scope.users = dataService.Users.query();
Hope this clarified it. I'm in a hurry, so ask more concrete and I will provide more examples later on.

angular.service vs angular.factory

I have seen both angular.factory() and angular.service() used to declare services; however, I cannot find angular.service anywhere in official documentation.
What is the difference between the two methods?
Which should be used for what (assuming they do different things)?
angular.service('myService', myServiceFunction);
angular.factory('myFactory', myFactoryFunction);
I had trouble wrapping my head around this concept until I put it to myself this way:
Service: the function that you write will be new-ed:
myInjectedService <---- new myServiceFunction()
Factory: the function (constructor) that you write will be invoked:
myInjectedFactory <--- myFactoryFunction()
What you do with that is up to you, but there are some useful patterns...
Such as writing a service function to expose a public API:
function myServiceFunction() {
this.awesomeApi = function(optional) {
// calculate some stuff
return awesomeListOfValues;
}
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.awesome = myInjectedService.awesomeApi();
Or using a factory function to expose a public API:
function myFactoryFunction() {
var aPrivateVariable = "yay";
function hello() {
return "hello mars " + aPrivateVariable;
}
// expose a public API
return {
hello: hello
};
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.hello = myInjectedFactory.hello();
Or using a factory function to return a constructor:
function myFactoryFunction() {
return function() {
var a = 2;
this.a2 = function() {
return a*2;
};
};
}
---------------------------------------------------------------------------------
// Injected in your controller
var myShinyNewObject = new myInjectedFactory();
$scope.four = myShinyNewObject.a2();
Which one to use?...
You can accomplish the same thing with both. However, in some cases the factory gives you a little bit more flexibility to create an injectable with a simpler syntax. That's because while myInjectedService must always be an object, myInjectedFactory can be an object, a function reference, or any value at all. For example, if you wrote a service to create a constructor (as in the last example above), it would have to be instantiated like so:
var myShinyNewObject = new myInjectedService.myFunction()
which is arguably less desirable than this:
var myShinyNewObject = new myInjectedFactory();
(But you should be wary about using this type of pattern in the first place because new-ing objects in your controllers creates hard-to-track dependencies that are difficult to mock for testing. Better to have a service manage a collection of objects for you than use new() wily-nilly.)
One more thing, they are all Singletons...
Also keep in mind that in both cases, angular is helping you manage a singleton. Regardless of where or how many times you inject your service or function, you will get the same reference to the same object or function. (With the exception of when a factory simply returns a value like a number or string. In that case, you will always get the same value, but not a reference.)
Simply put ..
const user = {
firstName: 'john'
};
// Factory
const addLastNameFactory = (user, lastName) => ({
...user,
lastName,
});
console.log(addLastNameFactory(user, 'doe'));
// Service
const addLastNameService = (user, lastName) => {
user.lastName = lastName; // BAD! Mutation
return user;
};
console.log(addLastNameService(user, 'doe'));
Here are the primary differences:
Services
Syntax: module.service( 'serviceName', function );
Result: When declaring serviceName as an injectable argument you will be provided with the instance of a function passed to module.service.
Usage: Could be useful for sharing utility functions that are useful to invoke by simply appending ( ) to the injected function reference. Could also be run with injectedArg.call( this ) or similar.
Factories
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.
Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances.
Here is example using services and factory. Read more about AngularJS Service vs Factory.
You can also check the AngularJS documentation and similar question on stackoverflow confused about service vs factory.
TL;DR
1) When you’re using a Factory you create an object, add properties to it, then return that same object. When you pass this factory into your controller, those properties on the object will now be available in that controller through your factory.
app.controller('myFactoryCtrl', function($scope, myFactory){
$scope.artist = myFactory.getArtist();
});
app.factory('myFactory', function(){
var _artist = 'Shakira';
var service = {};
service.getArtist = function(){
return _artist;
}
return service;
});
2) When you’re using Service, Angular instantiates it behind the scenes with the ‘new’ keyword. Because of that, you’ll add properties to ‘this’ and the service will return ‘this’. When you pass the service into your controller, those properties on ‘this’ will now be available on that controller through your service.
app.controller('myServiceCtrl', function($scope, myService){
$scope.artist = myService.getArtist();
});
app.service('myService', function(){
var _artist = 'Nelly';
this.getArtist = function(){
return _artist;
}
});
Non TL;DR
1) Factory
Factories are the most popular way to create and configure a service. There’s really not much more than what the TL;DR said. You just create an object, add properties to it, then return that same object. Then when you pass the factory into your controller, those properties on the object will now be available in that controller through your factory. A more extensive example is below.
app.factory('myFactory', function(){
var service = {};
return service;
});
Now whatever properties we attach to ‘service’ will be available to us when we pass ‘myFactory’ into our controller.
Now let’s add some ‘private’ variables to our callback function. These won’t be directly accessible from the controller, but we will eventually set up some getter/setter methods on ‘service’ to be able to alter these ‘private’ variables when needed.
app.factory('myFactory', function($http, $q){
var service = {};
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK';
return _finalUrl
}
return service;
});
Here you’ll notice we’re not attaching those variables/function to ‘service’. We’re simply creating them in order to either use or modify them later.
baseUrl is the base URL that the iTunes API requires
_artist is the artist we wish to lookup
_finalUrl is the final and fully built URL to which we’ll make the call to iTunes makeUrl is a function that will create and return our
iTunes friendly URL.
Now that our helper/private variables and function are in place, let’s add some properties to the ‘service’ object. Whatever we put on ‘service’ we’ll be able to directly use in whichever controller we pass ‘myFactory’ into.
We are going to create setArtist and getArtist methods that simply return or set the artist. We are also going to create a method that will call the iTunes API with our created URL. This method is going to return a promise that will fulfill once the data has come back from the iTunes API. If you haven’t had much experience using promises in Angular, I highly recommend doing a deep dive on them.
Below setArtist accepts an artist and allows you to set the artist. getArtist returns the artist callItunes first calls makeUrl() in order to build the URL we’ll use with our $http request. Then it sets up a promise object, makes an $http request with our final url, then because $http returns a promise, we are able to call .success or .error after our request. We then resolve our promise with the iTunes data, or we reject it with a message saying ‘There was an error’.
app.factory('myFactory', function($http, $q){
var service = {};
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
service.setArtist = function(artist){
_artist = artist;
}
service.getArtist = function(){
return _artist;
}
service.callItunes = function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
}
return service;
});
Now our factory is complete. We are now able to inject ‘myFactory’ into any controller and we’ll then be able to call our methods that we attached to our service object (setArtist, getArtist, and callItunes).
app.controller('myFactoryCtrl', function($scope, myFactory){
$scope.data = {};
$scope.updateArtist = function(){
myFactory.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myFactory.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
});
In the controller above we’re injecting in the ‘myFactory’ service. We then set properties on our $scope object that are coming from data from ‘myFactory’. The only tricky code above is if you’ve never dealt with promises before. Because callItunes is returning a promise, we are able to use the .then() method and only set $scope.data.artistData once our promise is fulfilled with the iTunes data. You’ll notice our controller is very ‘thin’. All of our logic and persistent data is located in our service, not in our controller.
2) Service
Perhaps the biggest thing to know when dealing with creating a Service is that that it’s instantiated with the ‘new’ keyword. For you JavaScript gurus this should give you a big hint into the nature of the code. For those of you with a limited background in JavaScript or for those who aren’t too familiar with what the ‘new’ keyword actually does, let’s review some JavaScript fundamentals that will eventually help us in understanding the nature of a Service.
To really see the changes that occur when you invoke a function with the ‘new’ keyword, let’s create a function and invoke it with the ‘new’ keyword, then let’s show what the interpreter does when it sees the ‘new’ keyword. The end results will both be the same.
First let’s create our Constructor.
var Person = function(name, age){
this.name = name;
this.age = age;
}
This is a typical JavaScript constructor function. Now whenever we invoke the Person function using the ‘new’ keyword, ‘this’ will be bound to the newly created object.
Now let’s add a method onto our Person’s prototype so it will be available on every instance of our Person ‘class’.
Person.prototype.sayName = function(){
alert('My name is ' + this.name);
}
Now, because we put the sayName function on the prototype, every instance of Person will be able to call the sayName function in order alert that instance’s name.
Now that we have our Person constructor function and our sayName function on its prototype, let’s actually create an instance of Person then call the sayName function.
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'
So all together the code for creating a Person constructor, adding a function to it’s prototype, creating a Person instance, and then calling the function on its prototype looks like this.
var Person = function(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
alert('My name is ' + this.name);
}
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'
Now let’s look at what actually is happening when you use the ‘new’ keyword in JavaScript. First thing you should notice is that after using ‘new’ in our example, we’re able to call a method (sayName) on ‘tyler’ just as if it were an object - that’s because it is. So first, we know that our Person constructor is returning an object, whether we can see that in the code or not. Second, we know that because our sayName function is located on the prototype and not directly on the Person instance, the object that the Person function is returning must be delegating to its prototype on failed lookups. In more simple terms, when we call tyler.sayName() the interpreter says “OK, I’m going to look on the ‘tyler’ object we just created, locate the sayName function, then call it. Wait a minute, I don’t see it here - all I see is name and age, let me check the prototype. Yup, looks like it’s on the prototype, let me call it.”.
Below is code for how you can think about what the ‘new’ keyword is actually doing in JavaScript. It’s basically a code example of the above paragraph. I’ve put the ‘interpreter view’ or the way the interpreter sees the code inside of notes.
var Person = function(name, age){
//The line below this creates an obj object that will delegate to the person's prototype on failed lookups.
//var obj = Object.create(Person.prototype);
//The line directly below this sets 'this' to the newly created object
//this = obj;
this.name = name;
this.age = age;
//return this;
}
Now having this knowledge of what the ‘new’ keyword really does in JavaScript, creating a Service in Angular should be easier to understand.
The biggest thing to understand when creating a Service is knowing that Services are instantiated with the ‘new’ keyword. Combining that knowledge with our examples above, you should now recognize that you’ll be attaching your properties and methods directly to ‘this’ which will then be returned from the Service itself. Let’s take a look at this in action.
Unlike what we originally did with the Factory example, we don’t need to create an object then return that object because, like mentioned many times before, we used the ‘new’ keyword so the interpreter will create that object, have it delegate to it’s prototype, then return it for us without us having to do the work.
First things first, let’s create our ‘private’ and helper function. This should look very familiar since we did the exact same thing with our factory. I won’t explain what each line does here because I did that in the factory example, if you’re confused, re-read the factory example.
app.service('myService', function($http, $q){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
});
Now, we’ll attach all of our methods that will be available in our controller to ‘this’.
app.service('myService', function($http, $q){
var baseUrl = 'https://itunes.apple.com/search?term=';
var _artist = '';
var _finalUrl = '';
var makeUrl = function(){
_artist = _artist.split(' ').join('+');
_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
return _finalUrl;
}
this.setArtist = function(artist){
_artist = artist;
}
this.getArtist = function(){
return _artist;
}
this.callItunes = function(){
makeUrl();
var deferred = $q.defer();
$http({
method: 'JSONP',
url: _finalUrl
}).success(function(data){
deferred.resolve(data);
}).error(function(){
deferred.reject('There was an error')
})
return deferred.promise;
}
});
Now just like in our factory, setArtist, getArtist, and callItunes will be available in whichever controller we pass myService into. Here’s the myService controller (which is almost exactly the same as our factory controller).
app.controller('myServiceCtrl', function($scope, myService){
$scope.data = {};
$scope.updateArtist = function(){
myService.setArtist($scope.data.artist);
};
$scope.submitArtist = function(){
myService.callItunes()
.then(function(data){
$scope.data.artistData = data;
}, function(data){
alert(data);
})
}
});
Like I mentioned before, once you really understand what ‘new’ does, Services are almost identical to factories in Angular.
The clue is in the name
Services and factories are similar to one another. Both will yield a singleton object that can be injected into other objects, and so are often used interchangeably.
They are intended to be used semantically to implement different design patterns.
Services are for implementing a service pattern
A service pattern is one in which your application is broken into logically consistent units of functionality. An example might be an API accessor, or a set of business logic.
This is especially important in Angular because Angular models are typically just JSON objects pulled from a server, and so we need somewhere to put our business logic.
Here is a Github service for example. It knows how to talk to Github. It knows about urls and methods. We can inject it into a controller, and it will generate and return a promise.
(function() {
var base = "https://api.github.com";
angular.module('github', [])
.service('githubService', function( $http ) {
this.getEvents: function() {
var url = [
base,
'/events',
'?callback=JSON_CALLBACK'
].join('');
return $http.jsonp(url);
}
});
)();
Factories implement a factory pattern
Factories, on the other hand are intended to implement a factory pattern. A factory pattern in one in which we use a factory function to generate an object. Typically we might use this for building models. Here is a factory which returns an Author constructor:
angular.module('user', [])
.factory('User', function($resource) {
var url = 'http://simple-api.herokuapp.com/api/v1/authors/:id'
return $resource(url);
})
We would make use of this like so:
angular.module('app', ['user'])
.controller('authorController', function($scope, User) {
$scope.user = new User();
})
Note that factories also return singletons.
Factories can return a constructor
Because a factory simply returns an object, it can return any type of object you like, including a constructor function, as we see above.
Factories return an object; services are newable
Another technical difference is in the way services and factories are composed. A service function will be newed to generate the object. A factory function will be called and will return the object.
Services are newable constructors.
Factories are simply called and return an object.
This means that in a service, we append to "this" which, in the context of a constructor, will point to the object under construction.
To illustrate this, here is the same simple object created using a service and a factory:
angular.module('app', [])
.service('helloService', function() {
this.sayHello = function() {
return "Hello!";
}
})
.factory('helloFactory', function() {
return {
sayHello: function() {
return "Hello!";
}
}
});
All the answers here seem to be around service and factory, and that's valid since that was what was being asked about. But it's also important to keep in mind that there are several others including provider(), value(), and constant().
The key to remember is that each one is a special case of the other. Each special case down the chain allowing you to do the same thing with less code. Each one also having some additional limitation.
To decide when to use which you just see which one allows you to do what you want in less code. Here is an image illustrating just how similar they are:
For a complete step by step breakdown and quick reference of when to use each you can visit the blog post where I got this image from:
http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/
app.factory('fn', fn) vs. app.service('fn',fn)
Construction
With factories, Angular will invoke the function to get the result. It is the result that is cached and injected.
//factory
var obj = fn();
return obj;
With services, Angular will invoke the constructor function by calling new. The constructed function is cached and injected.
//service
var obj = new fn();
return obj;
Implementation
Factories typically return an object literal because the return value is what's injected into controllers, run blocks, directives, etc
app.factory('fn', function(){
var foo = 0;
var bar = 0;
function setFoo(val) {
foo = val;
}
function setBar (val){
bar = val;
}
return {
setFoo: setFoo,
serBar: setBar
}
});
Service functions typically do not return anything. Instead, they perform initialization and expose functions. Functions can also reference 'this' since it was constructed using 'new'.
app.service('fn', function () {
var foo = 0;
var bar = 0;
this.setFoo = function (val) {
foo = val;
}
this.setBar = function (val){
bar = val;
}
});
Conclusion
When it comes to using factories or services they are both very similar. They are injected into a controllers, directives, run block, etc, and used in client code in pretty much the same way. They are also both singletons - meaning the same instance is shared between all places where the service/factory is injected.
So which should you prefer? Either one - they are so similar that the differences are trivial. If you do choose one over the other, just be aware how they are constructed, so that you can implement them properly.
I have spent some time trying to figure out the difference.
And i think the factory function uses the module pattern and service function uses the standard java script constructor pattern.
The factory pattern is more flexible as it can return functions and values as well as objects.
There isn't a lot of point in the service pattern IMHO, as everything it does you can just as easily do with a factory. The exceptions might be:
If you care about the declared type of your instantiated service for some reason - if you use the service pattern, your constructor will be the type of the new service.
If you already have a constructor function that you're using elsewhere that you also want to use as a service (although probably not much use if you want to inject anything into it!).
Arguably, the service pattern is a slightly nicer way to create a new object from a syntax point of view, but it's also more costly to instantiate. Others have indicated that angular uses "new" to create the service, but this isn't quite true - it isn't able to do that because every service constructor has a different number of parameters. What angular actually does is use the factory pattern internally to wrap your constructor function. Then it does some clever jiggery pokery to simulate javascript's "new" operator, invoking your constructor with a variable number of injectable arguments - but you can leave out this step if you just use the factory pattern directly, thus very slightly increasing the efficiency of your code.

Resources