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.
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
Is it possible to have a service with custom methods AND the NgResource functionality?
Or do I have to create and manage 2 objects throughout the application? One for $resource (a factory), another one for other things like keeping values after routing (a .service for example).
I mean, all the examples I read implementing NgResource like a service shows a factory object returning only ONE thing, the $resource component. Like this:
.factory('User', function($resource){
return $resource(URL + ':id', {}, {
edit: {method:'PUT'}
....
....
});
This is useful and clear. Just call: User.edit(...);
What if I need a custom method to do some process, like:
User.calculateSomethingAboutTheUser()
What if I need to remember the user values after routing? I'm accomplishing this using a service (.service), called User, like this in the controller:
$scope.user = User;
I can't do that with the factory example because it's always returning the $resource object.
actually $http and it's abstraction $resource are just for loading data from server side, it's data layer. and it's better to declare additional service for calculations (store some state and so on) and it will be business logic layer. then you declare some directives which help you to display/get data (eg user input). and it's presentation layer. those directives call methods on your business logic services and BL services call data layer if needed.
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')...
Laravel 5 uses put/patch verbs to update a resource while Angular ng.resource uses post by default for both create and update. How to globally set Laravel's Route::resource to follow the Angular behavior (a Laravel route for each ng resource)?
(It's also possible to make Angular compatible to Laravel, but I am not sure which approach is better.)
I don't know laravel's REST capabilities. But still i would suggest to modify Angular's behaviour.
PUT
Implementing PUT its quite easy.
You can modify behaviour of ng-resource while you are creating factory with $resource(url, parameters, actions), third parameter describes custom actions ...
In https://docs.angularjs.org/api/ngResource/service/$resource there is example about creating PUT method which will be available as update on service and $update on instance. :
app.factory('Notes', function($resource) {
return $resource('/notes/:id', null,
{
'update': { method:'PUT' }
});
}]);
// In our controller we get the ID from the URL using ngRoute and $routeParams
// We pass in $routeParams and our Notes factory along with $scope
app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
function($scope, $routeParams, Notes) {
// First get a note object from the factory
var note = Notes.get({ id:$routeParams.id });
$id = note.id;
// Now call update passing in the ID first then the object you are updating
Notes.update({ id:$id }, note);
// This will PUT /notes/ID with the note object in the request payload
});
PATCH
Creating PATCH behaviour is theoretically also possible, it is described here - Partial Updates (aka PATCH) using a $resource based service?
But I wouldn't do that with ng-resource. You can do many things by defining transformRequest or transformResponse function (i use this for utilizing Java Spring REST API). But still ng-resource doesn't support PATCH on its own so If you need I'd rather try different layer for REST.
That's wrong, you can use PUT/PATCH with angularjs too, please read about it at $http reference page
Shortcut methods
Shortcut methods are also available. All shortcut methods require passing in the URL, and request data must be passed in for POST/PUT requests.
$http.get('/someUrl').then(successCallback);
$http.post('/someUrl', data).then(successCallback);
Complete list of shortcut methods:
$http.get
$http.head
$http.post
$http.put
$http.delete
$http.jsonp
$http.patch
I started playing with Angular.js recently, and got a demo project working pretty well. However, when I attempted to load the data from a backend web service versus just a hard coded array I started getting hung up. Specifically the page doesnt seem to properly data bind after i set the $scope using $.getJSON().done(...). Instead of just assigning a value to $scope after .getJSON is done, should I be doing it somewhere else/differently? I searched high and low and really couldnt find any good examples of angular thats pulling intial data from a backend.
Thanks in advance for any help with this!
Since you are trying to update the $scope outside of Angular you will have to make your model changes using the $apply method on the scope.
Maybe something like:
$.getJSON('ajax/test.json', function(data) {
$scope.$apply(function(){
$scope.modelData = data;
});
});
The preferred way to access a backend with AngularJS would be to use the $http or $resource service in place of jQuery. You won't have to use $scope.$apply you can just update your $scope.modelData directly.
This post has a good fiddle of updating a model outside of Angular code.
or instead of wrapping with apply, just call it at the end of the callback function like
$.getJSON('ajax/test.json', function(data) {
$scope.data = data;
$scope.$apply();
});