Goodmorning,
i wanted to know if there's a way to attach by default a promises, i'll explain better....
module.factory('serviceName', function($http) {
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
return {
call1: function(callback) {
return $http.post('url1/something').then(callback);
},
call2: function(param1, param1, callback) {
return $http.post('url2/something', $.param({param1: param1, param2: param2, })).then(callback);
}
};
});
this is basically my service and i would like to know if there's a way of chaining a promise at the end of each of this call using something like $http.default.something
this would be really helpful :D
if there's a way of chaining a promise
Yes,
You can chain promises to create code flows
One of advantages: Error propagates, so you can catch it on the end of the
chain
Reference how chain promises works
About your example:
I don't think its a good way to use callback when $http.post returns promise itself.
If you want to create factory return promise, you can write:
var request = function(data) {
var deferred = $q.defer();
var configHttp = {
method: 'POST',
url: 'some URL'
};
if (data !== undefined) {
configHttp.data = data;
}
$http(configHttp).success(function(data, status, headers) {
if (data.error === undefined) {
deferred.resolve(data);
} else {
deferred.reject(data);
}
}).error(function(data, status, headers) {
deferred.reject(data);
});
return deferred.promise;
}
return {
call1: function(param1) {
return request('get_1', {param: param1});
},
call2: function(param2) {
return request('get_2', {param: param2});
}
So in controller we can write:
serviceName.call1..then(function(result)
{
//....
}, function(error) {
alert(error.message);
});
Related
Looking to get the right syntax to do the following :
1) empty object results = {}
2) first webservice call finished = results.webservice1 = data;
3) second webservice call finished = results.webservice2 = data;
4) Complete
I have something like this but syntax doesn't feel right
function getClaimSummary(filter) {
let deferred = $q.defer();
$http.post(configSettings.Api.GetClaimSummary, filter, { withCredentials : true })
.success(function(data){
deferred.resolve(data);
})
.error(function(error){
deferred.reject(error);
});
return deferred.promise;
}
function getPolicySummary(filter) {
let deferred = $q.defer();
$http.post(configSettings.Api.GetPolicySummary, filter, { withCredentials : true })
.success(function(data){
deferred.resolve(data);
})
.error(function(error){
deferred.reject(error);
});
return deferred.promise;
}
function calculateAccumulations(filter){
service.result = {};
//Get Claims Summary
getClaimSummary(filter).then(function(data){
service.result.claims = data;
}).then(getPolicySummary(filter).then(function(data){
service.result.policy = data;
showAccumulations();
}));
}
$http itself already returns a promise, so there's no need to create your own, you could also handle both promises at the same time instead of waiting for eachother like so:
function getClaimSummary(filter) {
return $http.post(configSettings.Api.GetClaimSummary, filter, { withCredentials : true });
}
function getPolicySummary(filter) {
return $http.post(configSettings.Api.GetPolicySummary, filter, { withCredentials : true });
}
function calculateAccumulations(filter){
service.result = {};
//Get Claims Summary
$q.all({
claims: getClaimSummary(filter),
policy: getPolicySummary(filter)
}).then(function (result) {
service.result = result;
});
}
You could even save some duplicate code doing it like so:
function fetchData(type, filter) {
return $http.post(configSettings.Api[type], filter, { withCredentials : true });
}
function calculateAccumulations(filter){
service.result = {};
//Get Claims Summary
$q.all({
claims: fetchData('GetClaimSummary', filter),
policy: getPolicySummary('GetPolicySummary', filter)
}).then(function (result) {
service.result = result;
});
}
More information about $q can be found here.
This code fetches categories and give them to controller.
sampleApp.factory('SCService', function($http, $q) {
var SuperCategories = [];
var SCService = {};
SCService.GetSuperCategories = function() {
var req = {
method: 'POST',
url: SuperCategoryURL,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: "action=GET"
};
if ( SuperCategories.length == 0 ) {
return $http(req).then(function (response) {
SuperCategories = response.data;
return SuperCategories;
});
}else {
return $q.when(SuperCategories);
}
}
return SCService;
});
I think code is perfect until there is no error in http request.
My query is how to do error handling (try catch or something like that), in case if server have some issue or may be cgi-script have some issue and not able to server the request.
Angular promises use a method catch for that.
return $http(req).then(function (response) {
SuperCategories = response.data;
return SuperCategories;
}).catch(function(error) {
// Do what you want here
});
You should use also finally :
return $http(req).then(function (response) {
SuperCategories = response.data;
return SuperCategories;
}).catch(function(error) {
// Do what you want here
}).finally(function() {
// Always executed. Clean up variables, call a callback, etc...
});
Write like
return $http(req).then(function (response) {
//success callback
},
function(){
//Failure callback
});
Use callback methods from controller Like
Controller.js
service.GetSuperCategories(function (data) {console.log('success'},function (error){console.log('error'});
service.js
sampleApp.factory('SCService', function($http, $q) {
var SuperCategories = [];
var SCService = {};
SCService.GetSuperCategories = function(successMethod,errorMethod) {
var req = {
method: 'POST',
url: SuperCategoryURL,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: "action=GET"
};
return $http(req).then(successMethod(data),
errorMethod(error));
}
return SCService;
});
You can use the .success and .error methods of $http service, as below
$http(req).success(function(data, status, headers){
// success callback: Enters if status = 200
}).error(function(status, headers){
// error callback: enters otherwise
});
I wrote a wrapper for the $http service in angular using a service. Why do i have to return bothe the http call and my result to have it available in a controller?
this is the function in the service:
this.fetchData = function(url, parameters)
{
if (parameters)
{
return $http.get(url, {params: parameters}).then(
function (response) {
console.log(response);
return response.data.data;
},
function (response) {
console.log(response);
});
}
else
{
return $http.get(url).then(
function (response) {
console.log(response);
},
function (response) {
console.log(response);
}
);
}
}
and this is where i call it in the controller:
test.fetchData('/jewelry-room/move-user.action', {user:2000, task:7}).then(
function (response) {
console.log(response);
},
function (response) {
console.log(response);
}
);
Because what you return from the factory is a promise: return $http.get().then(). Since your factory has the callback function inside then, so the promise is resolved. In this case, the function inside controller then block will not be called.
You need to return again in order to have access to the response data inside the controller.
Alternatively, just return $http.get() from the factory.
You could just return the promise to your controller by using $q:
var fetchData = function (url, params) {
if (params) {
var deferred = $q.defer();
$http.get(url, {params: params}).success(deferred.resolve).error(deferred.reject)
return deferred.promise;
} else {
var deferred = $q.defer();
$http.get(url).success(deferred.resolve).error(deferred.reject)
return deferred.promise;
}
}
Then inside your controller you can handle the promise.
I know I could do this:
angular.module('app.services').service('Resources', function ($q) {
this.ProductData = function() {
var deferred = $q.defer();
$http.get(url)
.then(function(result) {
deferred.resolve(result);
}, function() {
defered.reject("error");
});
return deferred.promise;
}
});
But could I avoid creating deferred obj, but still be able to do both resolve and reject?
angular.module('app.services').service('Resources', function () {
this.ProductData = function() {
return $http.get(url)
.then(function (result) {
// how would I do 'deferred.resolve or deferred.reject' here?
}, function () {
// how would I do 'deferred.reject' here?
});
}
});
You are right to avoid creating a deferred and another promise for $http.
If you need to reject the promise while the actual $http call has succeeded, you'd need to return $q.reject():
return $http.get(url)
.then(function(result){
if (result.data.length === 0) return $q.reject("error");
return result;
}
I've created a service which consumes an API. I need to call this service from my controller with an argument that's passed in from a text input on a form.
myAppServices.factory('apiService', function ($http, $q) {
return {
getDocuments: function () {
return $http.get('/api/documents/',
{
params: {
id: '2' // this should not be hardcoded
}
})
.then(function (response) {
if (typeof response.data == 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
}, function (response) {
// something went wrong
return $q.reject(response.data);
});
},
}
My controller looks like this currently...
myApp.controller('homeController', function ($scope, apiService) {
var docs = function () {
apiService.getDocuments()
.then(function (data) {
$scope.docs = data; //console.log(data);
}, function (error) {
// promise rejected ... display generic no data found on table
console.log('error', error);
});
};
}
And my input is simply...
<input type="text" class="form-control" placeholder="Enter ID" ng-model="id">
How can I get the value entered into this input into my service so that I can return the data based on the ID value put into the text input?
You need to pass the parameter to the service method, there is some suggestions that you can consider it.
1-) the promise api and the method on your service.
The right way to use the $q is using the deferred object inself. your service could be like.
myAppServices.factory('apiService', function ($http, $q) {
return {
getDocuments: function (id) {
var deferred = $q.defer();
$http({
method: 'GET',
url: '/api/documents/',
params: {id: id}
}).success(function (response) {
if (typeof response.data == 'object') {
deferred.resolve(response.data);
} else {
deferred.reject(response.data);
}
}).error(function (response) {
deferred.reject(response.data);
});
return deferred.promise;
}
}
})
2-) your controller could be like.
myApp.controller('homeController', function ($scope, apiService) {
$scope.getDocs = function () {
apiService.getDocuments($scope.id)
.then(function (data) {
$scope.docs = data; //console.log(data);
}, function (error) {
// promise rejected ... display generic no data found on table
console.log('error', error);
});
};
});
You can just pass additional parameters in your service definition. Then when you use it in your controller, you can pass additional values.
myAppServices.factory('apiService', function ($http, $q) {
return {
getDocuments: function (param1, param2) {
}
Should be something along these lines:
In your controller
apiService.getDocuments($scope.id).then...
In your service
getDocuments: function (idVar) {
return $http.get('/api/documents/',
{
params: {
id: idVar // this should not be hardcoded
}
})