According to the Angular documentation for $http, it seems that the constructor
$http(config)
and the functions
$http.get(...)
both return the same things - HttpPromises.
So what is the difference between them? Or are they just two ways to write the exact same thing?
$http.get(...), as said in the doc you gave link to, is a shortcut method to perform GET request. You won't be able to make any other type of request with $http.get - GET only. Note that POST, PUT, HEAD and DELETE have their corresponding shortcut methods too.
All these methods, however, are essentially the $http(config) calls - with method parameter pre-specified. Here's how it's done (1.3.6 source):
createShortMethods('get', 'delete', 'head', 'jsonp');
// ...
function createShortMethods(names) {
forEach(arguments, function(name) {
$http[name] = function(url, config) {
return $http(extend(config || {}, {
method: name,
url: url
}));
};
});
}
Still, sometimes it's more convenient to use $http(config) syntax - for example, if one has to choose the request method based on some external conditions that should be easy to switch. Note that if you don't specify method property in config, GET is used:
function $http(requestConfig) {
var config = {
method: 'get',
transformRequest: defaults.transformRequest,
transformResponse: defaults.transformResponse
};
// ... some checks skipped
extend(config, requestConfig);
}
Related
I'm using ngResource to handle my models in my Ionic/Angular app and I'm having trouble figuring out how/if I can make custom actions on the resource.
I'm storing my model instances in local storage and when I update a record, I want to update the local storage as well. I have this working, but I'm having to copy and paste code for multiple instances and would like to keep it DRY.
LogEntry.update($scope.timeLog, function(data) {
// update local storage
for ( var i = 0; i < logEntries.length; i++) {
if(logEntries[i].id == $scope.timeLog.id){
logEntries[i] = $scope.timeLog;
}
};
localStorageService.set('LogEntries', logEntries);
});
Here is a situation where I update a record, and after the promise returns I update local storage. I would like to make this repeatable, how I envision it being possible (based on other things I've seen in other frameworks and other languages) is something like:
LogEntry.update($scope.timeLog, function(data) {
// update local storage
LogEntry.updateLocalStorage($scope.timeLog);
});
My resource looks like:
.factory('LogEntry', function(config, $resource) {
return $resource(config.apiUrl + 'logentries/:id/', {}, {
'update': {
method:'PUT',
params: { id: '#id' }
}
});
})
Maybe I'm missing something in the docs, but it's pretty short and I'm not seeing a way to do this. Is something like LogEntry.updateLocalStorage($scope.timeLog); possible to store with ngResource, or do custom actions like that need to come from somewhere else? I'd like to keep my model-related actions together if possible.
You could use the transformResponse method in your resource definition. It's kind of a hack since you don't actually need to alter the response, but it allows you to preform actions with the returned data:
{function(data, headersGetter)|Array.<function(data, headersGetter)>}
transform function or an array of such functions. The transform function takes the http response body and headers and returns its transformed (typically deserialized) version. By default, transformResponse will contain one function that checks if the response looks like a JSON string and deserializes it using angular.fromJson. To prevent this behavior, set transformResponse to an empty array: transformResponse: []
https://docs.angularjs.org/api/ngResource/service/$resource
.factory('LogEntry', function (config, $resource) {
return $resource(config.apiUrl + 'logentries/:id/', {}, {
'update': {
'method': 'PUT',
'params': {
'id': '#id'
},
'transformResponse': function (data, header) {
// do stuff with data
return data;
}
}
});
})
That way it will always execute when you get a response but you could also use the transformRequest method, which will always fire on request regardless if you're getting a response.
{function(data, headersGetter)|Array.<function(data, headersGetter)>}
transform function or an array of such functions. The transform function takes the http request body and headers and returns its transformed (typically serialized) version. By default, transformRequest will contain one function that checks if the request data is an object and serializes to using angular.toJson. To prevent this behavior, set transformRequest to an empty array: transformRequest: []
https://docs.angularjs.org/api/ngResource/service/$resource
Which you choose depends on your usecase. Using transformRequest you could always save to localstorage, even when remote is down.
I would like to know how to pass headers to AngularJS $resource method
Here is the factory method
.factory('DataRepository', function ($resource) {
return $resource(serviceUrlPrefix + '/api/v1/AppList/:id', { id: '#id' }, { 'query': { method: 'GET', isArray: false }, 'update': { method: 'PUT', AppList: '#req', headers: { 'X-Requested-With': 'XmlHttpRequest' } } });
});
Here is the call to the dataRepository
dataRepository.update({ id: req[uniqueIDColumn] }, req, function (data) {
},
function (error) {
});
This code works fine. But i have few queries
Question 1:
Rather than specifying the headers in the factory method , how can i specify it in the call to the factory method? I tried few methods but it didnt work out.
Question 2:
I specified the header in the update method in the factory. When i perform "Save" using that factory, that header has been taken by default. But i have specified it explicitly for PUT method. Right? Why and how?
Question 3:
If i would like to specify the header for the particular factory in common for all Http methods, what is the way to do it?
Question 4:
What is the nomenclature for passing the parameters and the significance of "#" symbol before parameter and also in the below part, AppList is the parameter name used in the WebAPI, is it mandatory that it should match the parameter name in the WebAPI method, if its not matching, its not working:(
AppList: '#req'
I'm afraid we don't use $resource, but it does depend on $http. We configure the header with the below. Not sure about the rest of your questions.
I will say that we also do not use $http directly. We created our own "requestHelper" service that we inject everywhere. That allows us to inject things before making calls to $http as well as catch the response before passing the result on to the real caller. Helps with common error handling.
Configure headers for $http:
module.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
}]);
Assume that, I am using the angular-resource - module with my ng-app. I don't able to understand the data handling easy and scale able way.. any one give me / show me a correct way to answering all this questions?
a) Generally how to fetch data from url in the angular.?
b) in case each of the controller may require different url and data if so how the fetch process added on each of controller.?
c) or need we make a service to provide the data according to the controllers parameters - if so how to pass parametes to service?
d) All above have GET, PUT and DELETE, 'POST` then how to handle all them - is all this need separate services?
Thanks in advance.
Use angular-resource as you said within a service/factory. It already provides a lot of your requirements:
myApp.factory("dataService", [
"$resource",
function ($resource) {
return $resource("http://someBaseUrl/:action/:id", {
id: "#id" // default parameters
},
{
// custom methods
update: { method: "PUT" },
doOtherStuff: { method: "GET", action: "DoOtherStuff" }
});
}
]);
The $resource default provides for the following REST compliant functions:
{
'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'}
};
Any other functions you have to include yourself, like the update and the doOtherStuff in the example above.
The :action part is an easy way to provide any custom action, that is not REST compliant.
Usage in controllers:
myApp.controller("myCtrl", [
"dataService",
function (dataService) {
// first parameter can be used for any extra query parameters
// second parameter always is a callback
var myData = dataService.query({}, function() {
// success
});
var mySingleInstance = dataService.get({ id: 12 });
this.doUpdate = function (entity) {
dataService.update(entity);
// Or, if the 'entity' is a resource entity:
// entity.$update();
}
this.customMethod = function () {
dataService.doOtherStuff();
}
}
]);
See https://docs.angularjs.org/api/ngResource/service/$resource for the full documentation
Doesn't matter whether I am posting or deleting etc.. I would write this:
$http({
method: ''
url: '',
data: '',
headers: ''
}).success(function(data, status, headers, config) {
//whatever happens on success
}).error(function(data, status, headers, config) {
//whatever happens on failure
});
what is the difference between doing the above or doing this:
$http({
method: ''
url: '',
data: '',
headers: ''
}).then(function(response) {
//success
},
function(response) {
//failed
};
Does one have advantages over the other? Did one come about later and there isn't much of a difference?
Just want to know the differences really and what people prefer to use and why.
From the $http docs:
Returns a promise object with the standard then method and two http
specific methods: success and error. The then method takes two
arguments a success and an error callback which will be called with a
response object. The success and error methods take a single argument
- a function that will be called when the request succeeds or fails respectively. The arguments passed into these functions are
destructured representation of the response object passed into the
then method.
Which means that both examples you posted actually do the same, since .success(function () { ... }) and .error(function () { ... }) are just aliases of .then(function () { ... }) and `.then(null, function () { ... }), respectively.
I believe that the .then() syntax came later, as everything was standardized on the $q API. .success() and .error() were probably left for backward-compatibility.
See the Changelog for 0.10.6 where it says "the $xhr service was replaced with $http with promise based apis."
I have the following two ways and they both seem to work:
angular.module('adminApp')
.factory('TestAccount', function ($http) {
return {
get: function (applicationId) {
return $http({
method: 'GET',
url: '/api/TestAccounts/GetSelect',
params: { applicationId: applicationId }
});
}
}
});
//angular.module('adminApp')
//.factory('TestAccount', function ($http) {
// var TestAccount = {};
// TestAccount.get = function (applicationId) {
// return $http({
// method: 'GET',
// url: '/api/TestAccounts/GetSelect',
// params: { applicationId: applicationId }
// });
// };
// return TestAccount;
//});
The second method came from an answer to a question I asked on stackoverflow. The first way was some changes I made to it.
Can someone tell me which is the more conventional way and if there is any difference between these two. For me the first way seems a bit more clean but I am not sure if I am missing out on some functionality by using it.
I used the following to call the service in both cases:
TestAccount.get(3).then(function (result) {
$scope.testAccounts = result.data;
}, function (result) {
alert("Error: No data returned");
});
Those two approaches are equally valid. I prefer the first variant. No need to start with an empty object, set a property and return the object when you can just return an object with the property.
Like Brian said, they're both equally valid.
The second way is more versatile. It lets you write a service that has multiple functions where some of those functions call other of those functions, in a way that is relatively easy to reason about.
Using that ability in a service defined entirely within a .factory method would probably be a bad idea, and you don't need it in this case anyway. But if you have one service for which you do need that versatility, it may be worth using that style for all services across the board.