I'm a bit confused with Angular. I have two factories, with code looks almost the same, because they performs CRUD operations on two different objects in db, and I want to make them DRY.
So I have idea to move common logic to separate service, and I want it to works something like that :
angular.module('app').factory('first',['commonService',function(commonService){
return new commonService('someSpecificVariable');
}])
and service :
angular.module('app').service('commonService',['someDep1',function(someDep1,someSpecificVariable){
var something = someSpecificVariable;
}]);
I looked at providers, but i need something to instantiate. How can I achieve this?
In another words I want create factory responsible for all crud operation requests for all app modules, because writing many factories just to handle http/crud don't looks ok for me.
Ok i descriped it quite bad.
SOLUTION Is it possible and in good form to reuse the same data factory in Angular?
Factories
They let you share code between controllers as well as making http calls to your API. They are really about making some reusable code that you can instantiate in your controllers to make your life easier and your controllers cleaner.
Simple Example
.factory('FindFriend', function ($http, $rootScope) {
return {
find: function (phone) {
return $http.get('http://130.211.90.249:3000/findFriend', { params: {phone:phone}})
},
add: function (id) {
return $http.get('http://130.211.90.249:3000/addFriend', { params: {friendid:id, user_id: $rootScope.session} })
},
deleteFriend: function (id) {
return $http.get('http://130.211.90.249:3000/deleteFriend', {params:{idfriends: id}})
}
}
})
Explanation
So above we can see a factory called FindFriend. The factory has 3 methods find add and delete. these are different http calls (in your code they shouldn't be all get methods but this is some old code I wrote).
They can be instantiated by adding them into the top of the controller and then calling there functions like FindFriend.add
Hope this sheds some light on factories for you.
I know how factories works, but i dont want to add bunch of functions responsible for each module. I wish to make service, which will replace patches to $http calls based of provided module name in constructor. ex 'orders' will make request :
$http.post('/api'+'orders'+'/lazy')...
Related
I was taught that we use factories/services to eliminate the duplicate coding. Here's a part of the code which works fine.
app.controller('ServicesCtrl',['$scope','DataFactory',function($scope,$http,DataFactory){
DataFactory.GetData('services1.json')
.then(function(response){
$scope.returnedData = response.data;
})
.catch(function(response){
console.log('Error in process',response.status,response.data);
});
}]);
app.controller('ContactCtrl',['$scope','DataFactory', function($scope,DataFactory){
DataFactory.GetData('location.json')
.then(function(response){
$scope.returnedData = response.data;
})
.catch(function(response){
console.log('Error in process',response.status,response.data);
});
}]);
app.factory('DataFactory',['$http',function($http){
var factory = {};
factory.GetData = function(path) {
return $http.get(path);
}
return factory;
}]);
My question is 1. Why use services/factories to make such ajax calls when we have to work on the promises inside controllers? I mean, I have to make the same .then and .catch calls in both the controllers here. Where is the efficiency in it? Is there any better way to do this? Or am I doing this wrong? Is it possible to to work on those promises inside the factories and return the response.data to different controllers?
The thing here is re-usability of code . Now suppose you have a service called
angular.module('test')
.service('testService', function ($http) {
this.getBidsUser = function ($username) {
var endpoint = "bids/users/"+$username;
return $http({
method: 'get',
url: endpoint
});
};
}
which returns bids of a user . You might want to use the same information in different views. So its a good idea to use service so that you dont have to rewrite same code again .
Once more you might want to have all the same end point related service on the same service for maintainability .
You might need to change end points for a service which will be hectic if you do not use service pattern .
Promises arr call backs . If you process those promises inside a service it will not be easy to maintain caller timeline .
Hi we use factories and services
to make the application more modular,
to have the possibility to reuse the code,
to hide the implementation detail
For example a service which makes an http call it may be seen as an high level "service" which gives you back the required object, indipendently by the call type and it's reusable at high level.
The service allows to customize the call parameters, maybe avoiding that some of them are to be specified by the calling controller. Or it can do some preprocessing or post processing, it can do some caching and so on. And its portable, so you can call it each time you need.
For your last question
Is it possible to to work on those promises inside the factories and
return the response.data to different controllers?
Maybe it's possible, but may be complex to implement as it has to do with the timing of the response. Instead i suggest you the $resource service in the module ngResource, which can already do what you neeed.
See docs:
AngularJs Tutorial on $resource
Angularjs Programming guide on $resource
I am using Angular's $http for get, post, put and delete operations. Right now i have written this code in my Angular controller.
-- Now --
I want to use $resource instead of $http and want to place this data calls in a factory. After searching on so many websites i found this:
"use strict";
angular.module("app")
.factory('someFactoryName', function ($resource) {
return $resource('/foo/bar/:id', { id: '#_id' }, {
update: {
method: 'PUT' // this method issues a PUT request
}
});
})
Now i can use this factory in my controller like this:
$scope.entry = new someFactoryName();
$scope.entry.$save(function (response) {
//some code
});
Till here everything is fine.
-- Now what i want to achieve --
I have seen John Papa's Angular1 Style guide and i found this section, the code he demonstrated is very good i want to achieve the same thing i mean he called the ajax call and handled the response in the separate factory but here my case is little different. My only challenge is that he have used $http and i want to use $resource but for $resource i already have a factory then how can i write the response handling code in the same factory in which $resource is configured. I have 2 ideas in mind:
I can define one more factory and can inject this factory into new one,
Somehow write the code in this same factory
I don't know which one is best and how to achieve it, if you have any idea please help. Thanks.
I would suggest the first option.
Separation of concerns is important.
Yesterday, I heard a colleague state that the factory in angular is not the same as the factory pattern. I'm curious about if this is a valid statement and why.
Normally factories will create you an instance of an object. From looking at our code, it looks like the factory is a wrapper or object that can be called for the related web services as well, so GET, PUT, POST, PATCH, DELETE. There are some instances, where this varies, however for the most part, it looks like something that helps interact with the related web services.
Having a factory that returns objects just based on "GET" seems like it would align more with a traditional factory pattern, but the fact that we deal with the other verbs, makes me think that is where things deviate from the pattern.
Can someone confirm if this is the standard way to use angular factories and if so, if my intuition/thoughts are correct, or if I'm missing something?
Update
There as a request to provide code as to what I'm talking about. I did some googling for angular factory examples, to see if others are doing similar stuff as to what I'm seeing at my work. Which I found the following example: http://weblogs.asp.net/dwahlin/using-an-angularjs-factory-to-interact-with-a-restful-service
When you look at the example, you'll notice that the "dataFactory" does not just have a GET, it has other HTTP verbs too. Is this bad practice from the user base, or is it the standard way to use it and the factory is different from the design pattern?
Factory is a recipe of Provider in Angular and a form of Factory pattern, which is simply a process of one object takes responsibility to create other objects.
The example you referred is also an implementation of Factory pattern though not ideal, dataFactory creates and returns a proxy kind object which will be used in another consuming class to perform CRUD operations. Don't confuse it with HTTP verbs which are nothing to do with Factory pattern. In other words, factory class can return an object that can contain any kind of operations.
An ideal way to implement factory class:
function Bird(type) {
this.type = type;
//constructor logic
this.fly= function () {
//other business logic
};
}
//Below class is a factory which creates object for requested Bird type
function BirdFactory() {
this.create = function(type) {
return new Bird(type);
};
}
Hope this clarifies.
So, this isn't the typical question of HOW to do it. I know it can be done with a service or a factory but I was wondering if someone could share what the advantages/disadvantages would be of just creating a basic service, injecting it into each controller, and then extending the service with functions from each controller. Something similar to the following example..
app.service('HelperService', function() {
return {};
});
app.controller('Controller1', function($scope, HelperService) {
$scope.somefunc = function() {
//do stuff here
};
HelperService.somefunc = $scope.somefunc;
});
app.controller('Controller2', function($scope, HelperService) {
HelperService.somefunc();
});
This works, and works well. I feel a bit stupid for asking this but it just seems like I'm missing something here as to why this isn't used or recommended?
It may work, but its a bad idea.
Controller2 HelperService.somefunc() won't exist until Controller1 has been instantiated. So theres an implicit dependency of Controller2 on Controller1
the code on HelperService isn't in one place where it can be understood together
if you are doing some sort of data manipulation in that function, it really should be operating on data encapsulated by the HelperService.
The service is a singleton and it will be instantiated once calling new on the function itself -- the function you pass in is essentially a constructor. This will create the empty object you are returning for use everywhere, but if you want to return an object in such a way it makes more sense to use .factory, but this is not a big deal.
At any rate, you can consider your code to conceptually do this:
var HelperService = function () {}
var helperService = new HelperService;
function Controller1() {
helperService.someFunc = function () {}
}
function Controller2() {
helperService.someFunc();
}
I would consider this a dangerous thing to do for a couple of reasons:
Controller1 must be instantiated before Controller2 or else somefunc won't be available to Controller2. Ideally the controllers would have no knowledge of each other.
You are coupling Controller/ViewModel (since you're using scope) with service level logic, but these should be decoupled. HelperService shouldn't know about the controllers either. Instead, you should be injecting a service that has an API that the controllers expect to use. This doesn't always have to be HelperService, it just has to look like HelperService to the controllers and its API shouldn't change.
Without knowing specifics about what you're trying to do, it's hard to advise. In general you may rethink what you want to do, but you can extend functionality of services with other services. Consider services to be in their own layer.
I'm trying to achieve a program structure like this:
The problem here is, when there is no apparent controller using the Features in the beginning, they are not instantiated and not registered in the FeatureRegistry, therefore they can't show up in the View. But what I would like is to achieve is that they show up in the view, then there template is loaded via ng-include and then in the template there are specific controllers for each feauture. These controllers are the ones that are using the Features.
The features are basically only there to tell about the location of templates and icons, which to use, and also to kick off the start of the Feature.
But back to my initial question:
How to instantiate the services even if they are not needed at the moment?
Or is there another function, that I can use for that instead of service? I would also like if you point me to that then :)
You can ask for it in the run part of your application, injector will invoke it.
angular.module("myApp", []).
factory("EagerService", function () {
console.log("I'm ready.");
}).
run(function (EagerService) {
console.log("EagerService is ready.");
});
Yet, as far as I understand, you have child/sub controllers that need this EagerService. Why don't you inject it there?
(Since this is relatively old - this answer is for future readers - but I stumbled across this question so maybe someone else will too) If you use providers/config blocks - they are done eagerly, so it's better to do eager initialization code there. You are/were probably thinking in terms of services/run blocks.
To demonstrate with code, this alert will not pop (assuming myServiceModule is a module that your application depends on and myService is not injected anywhere):
angular.module('myServiceModule', []).service('myService', function () {
alert("service");
// service
return {};
});
However this alert will pop even if no one is depending on the myProvider service:
angular.module('myProviderModule', []).provider('myProvider', function () {
alert("provider");
// Define your service here. Can be an array of inject-ables
// instead of a function.
this.$get = function () {
// service
return {};
};
});
You can see this in action in this plunker.
Read more about providers in the official documentation here.