I'm using Angular to develop commenting functionality for a web app.
Currently there are two sections in the application were a user can comment:
Category
Product
About 90% of the commenting functionality is the same for both sections and as such I would like to make this reusable - i.e write some service or controller that I can reference/use as a base.
So far, my research seems to point to using a factory service but unfortunately this doesn't seem to work (I've spent the whole day running through various tutorials).
It is quite possible that I am over thinking this and making it far too complicated but I honestly don't know which way to turn anymore.
Herewith a quick and dirty overview of what I have so far:
HTML view for the category
Controller for the category (receives data from service and posts data to service in order to bind data to model)
Service for the category (retrieve and stores all the necessary
data)
The product uses the same logic and a lot of the code in the service and controller will be duplicated.
I've merged the two services into one service successfully but I'm having trouble doing the same for the controller.
Do I:
Write a base controller that will communicate with the above mentioned service and that will hookup with the two existing controllers
OR
Write a factory/provider service that hooks up to the two existing controllers as well as the above mentioned service.
If you go the route of using a factory, you could put all the common functionality into its return object and reference that from your controllers.
Factory
angular.module('myModule').factory('CommonFunctions', function(){
return {
foo : foo,
bar : bar
}
function foo(){
console.log('foo');
};
function bar (){
console.log('bar');
};
}
Controller
angular.module('myModule')
.controller('myController', ['CommonFunctions', function(CommonFunctions) {
var vm = this;
vm.foo = CommonFunctions.foo();
vm.bar = CommonFunctions.bar();
}
angular's separation of service types ie:
for specific values
constant
value
(constant for specific values needed before other services are created)
for functions
factory
service
provider
(provider for specific instances when you need a services before other services are created, usually taking advantage of constants)
allow the ability to share data and ways to process that data between controllers and or directives, anything that can be a value can also be a constant, the only difference there being where they can be injected. Similarly any service can be rewritten to a factory or a provider, it is more your specific use case / what your more comfortable writing that would determine which to use, but really the best way to think about it is if you have a value that needs to be shared but is not needed inside angular.module.config then use value, otherwise use constant, now if you have a single function that you want to share, (maybe it processes that value in some way or maybe it just does something else) you should write it as a factory, then when you have a few of those factory's that deal with either that value, or anything else, you can combine them into a service or configure and combine them using a provider. here is a simple example (note i am using the recommended syntax for writing angular services):
'use strict';
var app = angular.module('test.app',[]);
app.constant('configureableValue',{defaultValue:55});
app.value('editableValue',{defaultValue:100,editedValue:null});
app.provider('configureValue',configureValueProvider);
configureValueProvider.$inject - ['configureableValue'];
function configureValueProvider(configureableValue){
var defaultVal = configureableValue.defaultValue,
originalVal = defaultVal;
return {
getValue:getValue,
setValue:setValue,
resetValue:resetValue,
'$get':providerFunc
};
function getValue(){
return defaultVal;
}
function setValue(val){
defaultVal = val;
}
function providerFunc(){
return {
get:function(){ return getValue(); },
reset:function(){ resetValue(); }
};
}
function resetValue(){
defaultVal = originalVal
}
}
// this factory is an example of a single function service, this should almost always be defined as a factory
app.factory('getEditableValue',getEditableValue);
getEditableValue.$inject = ['editableValue'];
function getEditableValue(editableValue){
return function(){
return editableValue.editedValue ? editableValue.editedValue : editableValue.defaultValue;
};
}
// same with this one
app.factory('setEditableValue',setEditableValue);
setEditableValue.$inject = ['editableValue'];
function setEditableValue(editableValue){
return function(val){
editableValue.editedValue = val;
}
}
// now this is an example of a service service collecting the factorys for an object with all the related behavior we need
app.service('editableService',editableService);
editableService.$inject = ['getEditableValue','setEditableValue'];
function editableService(getEditableValue,setEditableValue){
var self = this;
self.setVal = setEditableValue;
self.getVal = getEditableValue;
}
app.config(appConfig);
appConfig.$inject = ['configureValueProvider'];
function appConfig(configureValueProvider){
configureValueProvider.setValue('i changed '+ configureValueProvider.getValue() +' to this!!!!');
}
app.run(appRun);
appRun.$inject = ['configureValue','editableService'];
function appRun(configureValue,editableService){
console.log('before editing: ',editableService.getVal());
editableService.setVal('changed!!!');
console.log('after editing: ',editableService.getVal());
console.log('we changed this in the config func: ',configureValue.get());
configureValue.reset();
console.log('and now its back to the original value: ',configureValue.get());
}
i know thats a lot for a simple example, but there are a lot of features provided by angular, and many ways to use them, hopefully this helps.
Related
I am working with AngularJS for my latest project. In the documentation and tutorials all model data is put into the controller scope. I understand that is has to be there to be available for the controller and thus within the corresponding views.
However I dont think the model should actually be implemented there. It might be complex and have private attributes for example. Furthermore one might want to reuse it in another context/app. Putting everything into the controller totally breaks MVC pattern.
The same holds true for the behaviour of any model. If I would use DCI architecture and separate behaviour from the data model, I would have to introduce additional objects to hold the behaviour. This would be done by introducing roles and contexts.
DCI == Data Collaboration Interaction
Of course model data and behaviour could be implemented with plain javascript objects or any "class" pattern. But what would be the AngularJS way to do it? Using services?
So it comes down to this question:
How do you implement models decoupled from the controller, following AngularJS best practices?
You should use services if you want something usable by multiple controllers. Here's a simple contrived example:
myApp.factory('ListService', function() {
var ListService = {};
var list = [];
ListService.getItem = function(index) { return list[index]; }
ListService.addItem = function(item) { list.push(item); }
ListService.removeItem = function(item) { list.splice(list.indexOf(item), 1) }
ListService.size = function() { return list.length; }
return ListService;
});
function Ctrl1($scope, ListService) {
//Can add/remove/get items from shared list
}
function Ctrl2($scope, ListService) {
//Can add/remove/get items from shared list
}
I'm currently trying this pattern, which, although not DCI, provides a classical service / model decoupling (with services for talking to web services (aka model CRUD), and model defining the object properties and methods).
Note that i only use this pattern whenever the model object needs methods working on its own properties, that i'll probably use everywhere (such as improved getter/setters). I'm not advocating doing this for every service systematically.
EDIT:
I used to think this pattern would go against the "Angular model is plain old javascript object" mantra, but it seems to me now that this pattern is perfectly fine.
EDIT (2):
To be even clearer, I use a Model class only to factor simple getters / setters (e.g. : to be used in view templates). For big business logic, i recommend using separate service(s) that "know" about the model, but are kept separated from them, and only include business logic. Call it a "business expert" service layer if you want
service/ElementServices.js (notice how Element is injected in the declaration)
MyApp.service('ElementServices', function($http, $q, Element)
{
this.getById = function(id)
{
return $http.get('/element/' + id).then(
function(response)
{
//this is where the Element model is used
return new Element(response.data);
},
function(response)
{
return $q.reject(response.data.error);
}
);
};
... other CRUD methods
}
model/Element.js (using angularjs Factory, made for object creation)
MyApp.factory('Element', function()
{
var Element = function(data) {
//set defaults properties and functions
angular.extend(this, {
id:null,
collection1:[],
collection2:[],
status:'NEW',
//... other properties
//dummy isNew function that would work on two properties to harden code
isNew:function(){
return (this.status=='NEW' || this.id == null);
}
});
angular.extend(this, data);
};
return Element;
});
The Angularjs documentation clearly states:
Unlike many other frameworks Angular makes no restrictions or
requirements on the model. There are no classes to inherit from or
special accessor methods for accessing or changing the model. The
model can be primitive, object hash, or a full object Type. In short
the model is a plain JavaScript object.
— AngularJS Developer Guide - V1.5 Concepts - Model
So it means that's up to you how to declare a model.
It's a simple Javascript object.
I personally won't use Angular Services as they were meant to behave like singleton objects you can use, for example, to keep global states across your application.
DCI is a paradigm and as such there's no angularJS way of doing it, either the language support DCI or it doesn't. JS support DCI rather well if you are willing to use source transformation and with some drawbacks if you are not. Again DCI has no more to do with dependency injection than say a C# class has and is definitely not a service either. So the best way to do DCI with angulusJS is to do DCI the JS way, which is pretty close to how DCI is formulated in the first place. Unless you do source transformation, you will not be able to do it fully since the role methods will be part of the object even outside the context but that's generally the problem with method injection based DCI. If you look at fullOO.info the authoritative site for DCI you could have a look at the ruby implementations they also use method injection or you could have a look at here for more information on DCI. It's mostly with RUby examples but the DCI stuff is agnostic to that.
One of the keys to DCI is that what the system does is separated from what the system is. So the data object are pretty dumb but once bound to a role in a context role methods make certain behaviour available. A role is simply an identifier, nothing more, an when accessing an object through that identifier then role methods are available. There's no role object/class. With method injection the scoping of role methods is not exactly as described but close. An example of a context in JS could be
function transfer(source,destination){
source.transfer = function(amount){
source.withdraw(amount);
source.log("withdrew " + amount);
destination.receive(amount);
};
destination.receive = function(amount){
destination.deposit(amount);
destination.log("deposited " + amount);
};
this.transfer = function(amount){
source.transfer(amount);
};
}
As stated by other posters, Angular provides no out-of-the-box base class for modeling, but one can usefully provide several functions:
Methods for interacting with a RESTful API and creating new objects
Establishing relationships between models
Validating data before persisting to the backend; also useful for displaying real-time errors
Caching and lazy-loading to keep from making wasteful HTTP requests
State machine hooks (before/after save, update, create, new, etc)
One library that does all of these things well is ngActiveResource (https://github.com/FacultyCreative/ngActiveResource). Full disclosure--I wrote this library--and I have used it successfully in building several enterprise-scale applications. It's well tested, and provides an API that should be familiar to Rails developers.
My team and I continue to actively develop this library, and I'd love to see more Angular developers contribute to it and battle test it.
An older question, but I think the topic is more relevant than ever given the new direction of Angular 2.0. I would say a best practice is to write code with as few dependencies on a particular framework as possible. Only use the framework specific parts where it adds direct value.
Currently it seems like the Angular service is one of the few concepts that will make it to the next generation of Angular, so it's probably smart to follow the general guideline of moving all logic to services. However, I would argue that you can make decoupled models even without a direct dependency on Angular services. Creating self contained objects with only necessary dependencies and responsibilities is probably the way to go. It also makes life a lot easier when doing automated testing. Single responsibility is a buzz work these days, but it does make a lot of sense!
Here is an example of a patter I consider good for decoupling the object model from the dom.
http://www.syntaxsuccess.com/viewarticle/548ebac8ecdac75c8a09d58e
A key goal is to structure your code in a way that makes it just as easy to use from a unit tests as from a view. If you achieve that you are well positioned to write realistic and useful tests.
I've tried to tackle that exact issue in this blog post.
Basically, the best home for data modeling is in services and factories. However, depending on how you retrieve your data and the complexity of the behaviors you need, there are lots of different ways to go about the implementation. Angular currently has no standard way or best practice.
The post covers three approaches, using $http, $resource, and Restangular.
Here's some example code for each, with a custom getResult() method on the Job model:
Restangular (easy peasy):
angular.module('job.models', [])
.service('Job', ['Restangular', function(Restangular) {
var Job = Restangular.service('jobs');
Restangular.extendModel('jobs', function(model) {
model.getResult = function() {
if (this.status == 'complete') {
if (this.passed === null) return "Finished";
else if (this.passed === true) return "Pass";
else if (this.passed === false) return "Fail";
}
else return "Running";
};
return model;
});
return Job;
}]);
$resource (slightly more convoluted):
angular.module('job.models', [])
.factory('Job', ['$resource', function($resource) {
var Job = $resource('/api/jobs/:jobId', { full: 'true', jobId: '#id' }, {
query: {
method: 'GET',
isArray: false,
transformResponse: function(data, header) {
var wrapped = angular.fromJson(data);
angular.forEach(wrapped.items, function(item, idx) {
wrapped.items[idx] = new Job(item);
});
return wrapped;
}
}
});
Job.prototype.getResult = function() {
if (this.status == 'complete') {
if (this.passed === null) return "Finished";
else if (this.passed === true) return "Pass";
else if (this.passed === false) return "Fail";
}
else return "Running";
};
return Job;
}]);
$http (hardcore):
angular.module('job.models', [])
.service('JobManager', ['$http', 'Job', function($http, Job) {
return {
getAll: function(limit) {
var params = {"limit": limit, "full": 'true'};
return $http.get('/api/jobs', {params: params})
.then(function(response) {
var data = response.data;
var jobs = [];
for (var i = 0; i < data.objects.length; i ++) {
jobs.push(new Job(data.objects[i]));
}
return jobs;
});
}
};
}])
.factory('Job', function() {
function Job(data) {
for (attr in data) {
if (data.hasOwnProperty(attr))
this[attr] = data[attr];
}
}
Job.prototype.getResult = function() {
if (this.status == 'complete') {
if (this.passed === null) return "Finished";
else if (this.passed === true) return "Pass";
else if (this.passed === false) return "Fail";
}
else return "Running";
};
return Job;
});
The blog post itself goes into more detail on the reasoning behind why you might use each approach, as well as code examples of how to use the models in your controllers:
AngularJS Data Models: $http VS $resource VS Restangular
There's a possibility Angular 2.0 will offer a more robust solution to data modeling that gets everyone on the same page.
I am trying to use the same service for different modules. There are many modules so i tried to inject them in a parent module. Something like this:
var app=angular.module('myapp',['module_1','module_2',....,'module_n']);
var module_1=angular.module('myapp1',[]);
var module_2=angular.module('myapp2',[]);
var module_3=angular.module('myapp3',[]);
.
.
.
var module_n=angular.module('myappN',[]);
and the service which is common to all the n modules is like this:
.service('myService',function(){
...doing something here...
});
Now I am not able to figure out how to use this service for all the submodules.
With which module should I associate this service ?
I tried doing app.service('myService',function(){...}), but it did'nt work.
Where am I going wrong?
EDIT 1:
Moreover I am trying to share a variable with all these submodules using the service. I am not sure if, I am doing the right thing by using a service for sharing variable or should I use a Provider or Factory for this job.
EDIT 2:
I found these links, but I could not grasp the answer. Refer to them and please provide my answer
How to share a variable between multiple modules in AngularJS
Passing variable between controllers which are on different modules
Lets suppose you want to build a Service to share a certain variable between two Controllers. You should be able to use your Service doing the following:
MyService.js
// Lets suppose you want to share a certain variable between controllers
angular
.module('myApp')
.service('myService', function () {
// If you wish you can inject and use $scope
var vm = this;
// Variable to share
vm.sharedItem;
// Method to set a certain value into a variable
function setItem(item){
vm.sharedItem = item;
}
// Method to get that variable
function getItem(){
return vm.sharedItem;
}
// Exposing your methods
return {
setItem : setItem
getItem : getItem
}
});
SetController.js
angular
.module('myApp')
.controller('SetController', SetController);
// Inject your Service
function SetController(myService) {
var vm = this;
// variable used to set the value
vm.setMe = 'hello';
// Call `setItem()` method from `myService` -> sharedItem will get setMe value
myService.setItem(vm.setMe);
console.log("Set shared item "+vm.setMe);
};
GetController.js:
angular
.module('myApp')
.controller('GetController', GetController);
// Inject your Service
function SetController(myService) {
var vm = this;
// variable used to get shared the value
vm.getMe= null;
/* Call `getItem()` method from `myService` to get the shared
* value and assign it to `getMe`*/
vm.getMe = myService.getItem();
console.log("Got shared item "+vm.getMe);
};
I remind you can access this.var in your view using controllerName.var. It is a good solution to make sure you are using a certain controller. You can always use $scope if you wish.
I hope I've been helpful.
In my Angular app, I have some resource modules, each containing some cache factories.
For example,
projectRsrc.factory('getProjectCache', ['$cacheFactory', function($cacheFactory){
return $cacheFactory('getProjectCache');
}]);
I have a few of these to cache values received from the servers.
The problem is that at times I'd like to clear all the caches. So I want to put all the cacheFactories into one CacheCentralApp module and delete all the caches with a single call.
The trouble is, I don't know of any way to access other factories inside my module. So for instance, if I create a module CacheCentralApp, and in it, declare factories that provide cacheFactorys, how can I create a function in there that calls removeAll() on every cacheFactory?
I don't think it is possible to target all the factories of a certain module. I think however that another solution to your problem is to send a event that all factories has to be cleared. This will prevent that you will have to loop through all your factories and call a .clear() function on everyone.
You could send a event request with the following code:
$scope.$broadcast('clearAllCaches');
And listen to this event in every factory with:
$scope.$on('clearAllCaches', function() {
clearCache();
}
In a separate module you might create a factory for that:
var cacheModule = angular.module('CacheCentralApp', []);
cacheModule.factory('MyCacheFactory', ['$cacheFactory', function($cacheFactory) {
var cacheKeys = [];
return {
clearAll: function() {
angular.forEach(cacheKeys, function(key) {
$cacheFactory.get(key).removeAll();
});
},
get: function(key) {
if(cacheKeys.indexOf(key) == -1) {
cacheKeys.push(key);
return $cacheFactory(key);
} else {
return $cacheFactory.get(key);
}
}
}
}]);
To create new or get existing Cache you simply call MyCacheFactory.get(cacheName). To clear all the caches ever created in the factory you call MyCacheFactory.clearAll().
Note: I am not quite sure that Array.indexOf is available in every browser, you might want to use Lo-Dash or another library to make sure your code works.
I have this service I'd like to use, but it could happen that some parts of my application require the same service but with different parameters to use internally. Since services always refer to the same instance as far as I understand it, this would mean either manually having to edit the parameters everywhere before performing an action, or passing them in to every function. This would get messy very fast and I was wondering if it was possible to create a factory to initialise the different versions of the service I need.
Something like this, for instance:
function FooService(){
this.setParams = function(params){
...
}
};
function FooServiceFactory(){
return{
createService: function(name, params){
var serv = new FooService();
serv.setParams(params);
ServiceModule.service(name, serv);
}
}
};
You can create factories as well.
app.factory("InstantiateMe", [function() {
return function(params)
{
// some code
};
}]);
app.controller("Ctrl", ["InstantiateMe", function(InstantiateMe) {
var instance = new InstantiateMe({param: "value"});
}]);
In short, the factory function returns just that: a factory. Its return value can be an object, a function or, in this particular case, a constructor. You can this way instantiate multiple instances of your desired service.
Here is a nice article on the subject, elaborating on what I've summarised, that you may find useful.
Please bear with me here. I know there are other answers such as:
AngularJS: Service vs provider vs factory
However I still can't figure out when you'd use service over factory.
From what I can tell factory is commonly used to create "common" functions that can be called by multiple Controllers: Creating common controller functions
The Angular docs seem to prefer factory over service. They even refer to "service" when they use factory which is even more confusing! http://docs.angularjs.org/guide/dev_guide.services.creating_services
So when would one use service?
Is there something that is only possible or much easier done with service?
Is there anything different that goes on behind the scenes? Performance/memory differences?
Here's an example. Other than the method of declaration, they seem identical and I can't figure out why I'd do one vs the other. http://jsfiddle.net/uEpkE/
Update: From Thomas' answer it seems to imply that service is for simpler logic and factory for more complex logic with private methods, so I updated the fiddle code below and it seems that both are able to support private functions?
myApp.factory('fooFactory', function() {
var fooVar;
var addHi = function(foo){ fooVar = 'Hi '+foo; }
return {
setFoobar: function(foo){
addHi(foo);
},
getFoobar:function(){
return fooVar;
}
};
});
myApp.service('fooService', function() {
var fooVar;
var addHi = function(foo){ fooVar = 'Hi '+foo;}
this.setFoobar = function(foo){
addHi(foo);
}
this.getFoobar = function(){
return fooVar;
}
});
function MyCtrl($scope, fooService, fooFactory) {
fooFactory.setFoobar("fooFactory");
fooService.setFoobar("fooService");
//foobars = "Hi fooFactory, Hi fooService"
$scope.foobars = [
fooFactory.getFoobar(),
fooService.getFoobar()
];
}
Explanation
You got different things here:
First:
If you use a service you will get the instance of a function ("this"
keyword).
If you use a factory you will get the value that is returned by
invoking the function reference (the return statement in factory).
ref: angular.service vs angular.factory
Second:
Keep in mind all providers in AngularJS (value, constant, services, factories) are singletons!
Third:
Using one or the other (service or factory) is about code style.
But, the common way in AngularJS is to use factory.
Why ?
Because "The factory method is the most common way of getting objects into AngularJS dependency injection system. It is very flexible and can contain sophisticated creation logic. Since factories are regular functions, we can also take advantage of a new lexical scope to simulate "private" variables. This is very useful as we can hide implementation details of a given service."
(ref: http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821).
Usage
Service : 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.
Factory : Could be useful for returning a ‘class’ function that can then be new`ed to create instances.
So, use a factory when you have complex logic in your service and you don't want expose this complexity.
In other cases if you want to return an instance of a service just use service.
But you'll see with time that you'll use factory in 80% of cases I think.
For more details: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/
UPDATE :
Excellent post here :
http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html
"If you want your function to be called like a normal function, use
factory. If you want your function to be instantiated with the new
operator, use service. If you don't know the difference, use factory."
UPDATE :
AngularJS team does his work and give an explanation:
http://docs.angularjs.org/guide/providers
And from this page :
"Factory and Service are the most commonly used recipes. The only difference between them is that Service recipe works better for objects of custom type, while Factory can produce JavaScript primitives and functions."
allernhwkim originally posted an answer on this question linking to his blog, however a moderator deleted it. It's the only post I've found which doesn't just tell you how to do the same thing with service, provider and factory, but also tells you what you can do with a provider that you can't with a factory, and with a factory that you can't with a service.
Directly from his blog:
app.service('CarService', function() {
this.dealer="Bad";
this.numCylinder = 4;
});
app.factory('CarFactory', function() {
return function(numCylinder) {
this.dealer="Bad";
this.numCylinder = numCylinder
};
});
app.provider('CarProvider', function() {
this.dealerName = 'Bad';
this.$get = function() {
return function(numCylinder) {
this.numCylinder = numCylinder;
this.dealer = this.dealerName;
}
};
this.setDealerName = function(str) {
this.dealerName = str;
}
});
This shows how the CarService will always a produce a car with 4 cylinders, you can't change it for individual cars. Whereas CarFactory returns a function so you can do new CarFactory in your controller, passing in a number of cylinders specific to that car. You can't do new CarService because CarService is an object not a function.
The reason factories don't work like this:
app.factory('CarFactory', function(numCylinder) {
this.dealer="Bad";
this.numCylinder = numCylinder
});
And automatically return a function for you to instantiate, is because then you can't do this (add things to the prototype/etc):
app.factory('CarFactory', function() {
function Car(numCylinder) {
this.dealer="Bad";
this.numCylinder = numCylinder
};
Car.prototype.breakCylinder = function() {
this.numCylinder -= 1;
};
return Car;
});
See how it is literally a factory producing a car.
The conclusion from his blog is pretty good:
In conclusion,
---------------------------------------------------
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------
| Factory | Yes | Yes | No |
---------------------------------------------------
| Service | Yes | No | No |
---------------------------------------------------
| Provider| Yes | Yes | Yes |
---------------------------------------------------
Use Service when you need just a simple object such as a Hash, for
example {foo;1, bar:2} It’s easy to code, but you cannot instantiate
it.
Use Factory when you need to instantiate an object, i.e new
Customer(), new Comment(), etc.
Use Provider when you need to configure it. i.e. test url, QA url,
production url.
If you find you're just returning an object in factory you should probably use service.
Don't do this:
app.factory('CarFactory', function() {
return {
numCylinder: 4
};
});
Use service instead:
app.service('CarService', function() {
this.numCylinder = 4;
});
The concept for all these providers is much simpler than it initially appears. If you dissect a provider you and pull out the different parts it becomes very clear.
To put it simply each one of these providers is a specialized version of the other, in this order: provider > factory > value / constant / service.
So long the provider does what you can you can use the provider further down the chain which would result in writing less code. If it doesn't accomplish what you want you can go up the chain and you'll just have to write more code.
This image illustrates what I mean, in this image you will see the code for a provider, with the portions highlighted showing you which portions of the provider could be used to create a factory, value, etc instead.
(source: simplygoodcode.com)
For more details and examples from the blog post where I got the image from go to: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/
Both the factory and the service result in singleton objects which are able to be configured by providers and injected into controllers and run blocks. From the point of view of the injectee, there is absolutely no difference whether the object came from a factory or a service.
So, when to use a factory, and when to use a service? It boils down to your coding preference, and nothing else. If you like the modular JS pattern then go for the factory. If you like the constructor function ("class") style then go for the service. Note that both styles support private members.
The advantage of the service might be that it's more intuitive from the OOP point of view: create a "class", and, in conjunction with a provider, reuse the same code across modules, and vary the behavior of the instantiated objects simply by supplying different parameters to the constructor in a config block.
There is nothing a Factory cannot do or does better in comparison with a Service. And vice verse. Factory just seems to be more popular. The reason for that is its convenience in handling private/public members. Service would be more clumsy in this regard.
When coding a Service you tend to make your object members public via “this” keyword and may suddenly find out that those public members are not visible to private methods (ie inner functions).
var Service = function(){
//public
this.age = 13;
//private
function getAge(){
return this.age; //private does not see public
}
console.log("age: " + getAge());
};
var s = new Service(); //prints 'age: undefined'
Angular uses the “new” keyword to create a service for you, so the instance Angular passes to the controller will have the same drawback.
Of course you may overcome the problem by using this/that:
var Service = function(){
var that = this;
//public
this.age = 13;
//private
function getAge(){
return that.age;
}
console.log("age: " + getAge());
};
var s = new Service();// prints 'age: 13'
But with a large Service constant this\that-ing would make the code poorly readable.
Moreover, the Service prototypes will not see private members – only public will be available to them:
var Service = function(){
var name = "George";
};
Service.prototype.getName = function(){
return this.name; //will not see a private member
};
var s = new Service();
console.log("name: " + s.getName());//prints 'name: undefined'
Summing it up, using Factory is more convenient. As Factory does not have these drawbacks. I would recommend using it by default.
Even when they say that all services and factories are singleton, I don't agree 100 percent with that. I would say that factories are not singletons and this is the point of my answer. I would really think about the name that defines every component(Service/Factory), I mean:
A factory because is not a singleton, you can create as many as you want when you inject, so it works like a factory of objects. You can create a factory of an entity of your domain and work more comfortably with this objects which could be like an object of your model. When you retrieve several objects you can map them in this objects and it can act kind of another layer between the DDBB and the AngularJs model.You can add methods to the objects so you oriented to objects a little bit more your AngularJs App.
Meanwhile a service is a singleton, so we can only create 1 of a kind, maybe not create but we have only 1 instance when we inject in a controller, so a service provides more like a common service(rest calls,functionality.. ) to the controllers.
Conceptually you can think like services provide a service, factories can create multiple instances(objects) of a class
Services
Syntax: module.service( 'serviceName', function );
Result: When declaring serviceName as an injectable argument you will be provided the actual function reference 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 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.
Providers
Syntax: module.provider( 'providerName', function );
Result: When declaring providerName as an injectable argument you will be provided the value that is returned by invoking the $get method of the function reference passed to module.provider.
Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances but that requires some sort of configuration before being injected. Perhaps useful for classes that are reusable across projects? Still kind of hazy on this one.
Can use both the way you want : whether create object or just to access functions from both
You can create new object from service
app.service('carservice', function() {
this.model = function(){
this.name = Math.random(22222);
this.price = 1000;
this.colour = 'green';
this.manufacturer = 'bmw';
}
});
.controller('carcontroller', function ($scope,carservice) {
$scope = new carservice.model();
})
Note :
service by default returns object and not constructor function .
So that's why constructor function is set to this.model property.
Due to this service will return object,but but but inside that object will be constructor function which will be use to create new object;
You can create new object from factory
app.factory('carfactory', function() {
var model = function(){
this.name = Math.random(22222);
this.price = 1000;
this.colour = 'green';
this.manufacturer = 'bmw';
}
return model;
});
.controller('carcontroller', function ($scope,carfactory) {
$scope = new carfactory();
})
Note :
factory by default returns constructor function and not object .
So that's why new object can be created with constructor function.
Create service for just accessing simple functions
app.service('carservice', function () {
this.createCar = function () {
console.log('createCar');
};
this.deleteCar = function () {
console.log('deleteCar');
};
});
.controller('MyService', function ($scope,carservice) {
carservice.createCar()
})
Create factory for just accessing simple functions
app.factory('carfactory', function () {
var obj = {}
obj.createCar = function () {
console.log('createCar');
};
obj.deleteCar = function () {
console.log('deleteCar');
};
});
.controller('MyService', function ($scope,carfactory) {
carfactory.createCar()
})
Conclusion :
you can use both the way you want whether to create new object or
just to access simple functions
There won't be any performance hit , using one over the other
Both are singleton objects and only one instance is created per app.
Being only one instance every where their reference is passed.
In angular documentation factory is called service and also service is called service.
Factory and Service are the most commonly used method. The only difference between them is that the Service method works better for objects that need inheritance hierarchy, while the Factory can produce JavaScript primitives and functions.
The Provider function is the core method and all the other ones are just syntactic sugar on it. You need it only if you are building a reusable piece of code that needs global configuration.
There are five methods to create services: Value, Factory, Service, Provider and Constant. You can learn more about this here angular service, this article explain all this methods with practical demo examples.
.