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.
Related
I have the following function (credit) that wraps an AngularJS $http function in a way that it invokes browser XHR when running on desktop, but invokes cordova-plugin-advanced-http if on mobile.
It seems that this works when I use $http({method:'get/post'}...) but doesn't work if I call the convenience shortcuts like $http.get(...)
Can someone suggest what modification I need to make?
$provide.decorator('$http', ['$delegate', '$q', function($delegate, $q) {
// create function which overrides $http function
var $http = $delegate;
var wrapper = function () {
var url = arguments[0].url;
var method = arguments[0].method;
var isOutgoingRequest = /^(http|https):\/\//.test(url);
if (window.cordova && isOutgoingRequest) {
console.log ("**** -->"+method+"<-- using native HTTP with:"+url);
var d = $q.defer();
var options = {
method: method,
data: arguments[0].data,
headers: arguments[0].headers,
timeout: arguments[0].timeout
};
cordova.plugin.http.sendRequest(url,options,
function (succ) {
console.log ("*** Inside native HTTP success with:"+JSON.stringify(succ));
try {
if (options.headers && options.headers['x-parse']=='text')
d.resolve({"data":succ.data});
else
d.resolve({"data":JSON.parse(succ.data)});
return d.promise;
}
catch (e) {
d.resolve({"data":succ.data});
return d.promise;
}
},
function (err) {
console.log ("*** Inside native HTTP error");
d.reject(err);
return d.promise;
});
return d.promise;
}
else {
console.log ("**** "+method+" using XHR HTTP for "+url);
return $http.apply($http, arguments);
}
};
Object.keys($http).filter(function (key) {
return (typeof $http[key] === 'function');
}).forEach(function (key) {
wrapper[key] = function () {
// Apply global changes to arguments, or perform other
// nefarious acts.
// console.log ("KEY="+key);
return $http[key].apply($http, arguments);
};
});
return wrapper;
}]);
If I understood your intent correctly, the way you're assigning the HTTP methods that hang off wrapper won't invoke the contents of your wrapper function.
Note that the parameters of the $http convenience functions vary.
Examples:
GET is described as: get(url, [config])
POST is described as: post(url, data, [config])
With the above in mind, here's one way of delegating back to your wrapper function that switches between XHR and the Cordova plugin when the $http convenience methods are used:
wrapper[key] = function () {
var url = arguments[0];
if (['get', 'delete', 'head', 'jsonp'].indexOf(key) !== -1) {
// arguments[1] == config
return wrapper(Object.assign({
method: key,
url: url,
}, arguments[1]));
} else {
// POST, PUT, PATCH
// arguments[1] == data
// arguments[2] == config
return wrapper(Object.assign({
data: arguments[1],
method: key,
url: url,
}, arguments[2]));
}
};
Here is a working solution I eventually arrived at.
// Wraps around $http that switches between browser XHR
// or cordova-advanced-http based on if cordova is available
// credits:
// a) https://www.exratione.com/2013/08/angularjs-wrapping-http-for-fun-and-profit/
// b) https://gist.github.com/adamreisnz/354364e2a58786e2be71
$provide.decorator('$http', ['$delegate', '$q', function($delegate, $q) {
// create function which overrides $http function
var $http = $delegate;
var wrapper = function () {
var url;
var method;
url = arguments[0].url;
method = arguments[0].method;
var isOutgoingRequest = /^(http|https):\/\//.test(url);
if (window.cordova && isOutgoingRequest) {
console.log ("**** -->"+method+"<-- using native HTTP with:"+encodeURI(url));
var d = $q.defer();
var options = {
method: method,
data: arguments[0].data,
headers: arguments[0].headers,
timeout: arguments[0].timeout,
responseType: arguments[0].responseType
};
cordova.plugin.http.sendRequest(encodeURI(url),options,
function (succ) {
// automatic JSON parse if no responseType: text
// fall back to text if JSON parse fails too
if (options.responseType =='text') {
// don't parse into JSON
d.resolve({"data":succ.data});
return d.promise;
}
else {
try {
d.resolve({"data":JSON.parse(succ.data)});
return d.promise;
}
catch (e) {
console.log ("*** Native HTTP response: JSON parsing failed for "+url+", returning text");
d.resolve({"data":succ.data});
return d.promise;
}
}
},
function (err) {
console.log ("*** Inside native HTTP error: "+JSON.stringify(err));
d.reject(err);
return d.promise;
});
return d.promise;
}
else { // not cordova, so lets go back to default http
console.log ("**** "+method+" using XHR HTTP for "+url);
return $http.apply($http, arguments);
}
};
// wrap around all HTTP methods
Object.keys($http).filter(function (key) {
return (typeof $http[key] === 'function');
}).forEach(function (key) {
wrapper[key] = function () {
return $http[key].apply($http, arguments);
};
});
// wrap convenience functions
$delegate.get = function (url,config) {
return wrapper(angular.extend(config || {}, {
method: 'get',
url: url
}));
};
$delegate.post = function (url,data,config) {
return wrapper(angular.extend(config || {}, {
method: 'post',
url: url,
data:data
}));
};
$delegate.delete = function (url,config) {
return wrapper(angular.extend(config || {}, {
method: 'delete',
url: url
}));
};
return wrapper;
}]);
I need to finish all my ajax calls to enable a button, but I am not getting all my promises done before enabling the button.
I have this piece of code with all my ajax gets:
$q.all([
$scope.load_ocupacoes(),
$scope.load_tipos_pisos(),
$scope.load_tipos(),
$scope.load_caracteristicas(),
$scope.load_amenidades(),
$scope.load_subtipos(true, 'incluir')
]).then(function() {
console.log('loading complete !!!');
$scope.theglyphicon = 'fa fa-check fa-fw';
$scope.isDisabledButton = false;
});
Each load function is a $http.get, like that:
$scope.load_ocupacoes = function() {
$http.get(url_api_status_ocupacao)
.success(function(response) {
console.log(response);
$scope.status_ocupacoes = response;
})
.error(function(response) {
console.log(response);
ngToast.create({
className: 'danger',
content: 'Não foi possível recuperar a lista.'
});
});
};
I have also tried this way:
$scope.load_ocupacoes = function()
{$resource(url_api_status_ocupacao).query().$promise.then(function(response) {
console.log(response);
$scope.status_ocupacoes = response;
});
};
And this... but with the same problem:
$scope.load_ocupacoes = function() {
$timeout(function(){
$scope.$apply(function() {
$scope.status_ocupacoes = appFactory.recuperarLista(url_api_status_ocupacao)
.then(function(result) {
console.log(result);
$scope.status_ocupacoes = result;
});
});
});
};
But, I am getting the message 'loading complete !!!' before the end of all loading.
Is there any problem with this approach?
There could be more errors, but the basic misunderstanding is that $q.all takes promises, and all your functions return undefined (because they don't have a return statement) - so instead of getting six promises, your $q.all gets six undefineds. AFAIK, $http.get returns a promise by default, so one way to fix it would be to just add return statement to each of your functions, in front of $http.get, like this:
$scope.load_ocupacoes = function() {
return $http.get(url_api_status_ocupacao)
.then(function(response) {
});
};
I guess $q.all accept promises.
This must be apply to all other's related method.
$scope.load_ocupacoes = function() {
$http.get(url_api_status_ocupacao)
// use then instead success
.then(function(response) {
// return raw promise instead actual value
return response;
}, console.log('error));
};
$q.all requires an array of promises but your are providing a function which is neither returning any promise.
You can do this :
$q.all([
$http.get(url_api_status_ocupacao),
$http.get(url_api1),
$http.get(url_api2)
]).then(function() {
......
});
I have resolved my problem with this approach:
var promises = [appFactory.recuperarLista(url_api_status_ocupacao),
appFactory.recuperarLista(url_api_tipos_pisos),
appFactory.recuperarLista(url_api_caracteristicas),
appFactory.recuperarLista(url_api_amenidades)
];
$q.all(promises).then(function (responses) {
$scope.status_ocupacoes = responses[0];
$scope.tipos_pisos = responses[1];
$scope.caracteristicas = responses[2];
$scope.amenidades = responses[3];
}).then(function() {
console.log('All Loading completed !!!');
});
And I made a factory returning promises:
angular.module('starter.services', ['datatables'])
.factory('appFactory', function($http, $q) {
return {
recuperarLista: function(url) {
var deferred = $q.defer();
$http({ method: "GET", url: url })
.success(function (data, status, headers, config) {
deferred.resolve(data);
}).error(function (data, status, headers, config) {
deferred.reject(status);
});
console.log('loading for ' + url + ' was completed !!!');
return deferred.promise;
}
};
});
Now I am getting this console output:
loading for api/loadliststatusocupacoes was completed !!!
services.js:171
loading for api/loadlisttipospisos was completed !!!
services.js:171
loading for api/loadlistcaracteristicas was completed !!!
services.js:171
loading for api/loadlistamenidades was completed !!!
services.js:171
All Loading completed !!!
imovel-controller.js:690
I have an angularJS app that utilizes two services to retrieve data from a DB.
session.js
angular.module('RiskAssessment').service('session', ['dbInterface', function(dbInterface) {
this.getBatches = function () {
if (!this.batches) {
console.log("Retrieved Batches");
var that = this;
return this.pullBatches().then(function (data) {
that.batches = data; //Is this EVEN possible?
});
} else {
console.log("Didn't retrieve Batches");
}
return this.batches;
};
this.pullBatches = function () {
return dbInterface.pullBatches(this.getUserId());
};}]);
dbInterface.js
pullBatches: function(userId){
return $http.post('db_queries/get_batches.php', userId)
.then(function (response) {
console.log("get_batches.php POST Result: ", response.data);
return response.data;
})
.catch(function (response) {
console.log("Error post");
});
}
I want to able to get this.batches via getBatches() if it has already been retrieved and set. Otherwise, I'd like to use pullBatches() to retrieve and set this.batches. The answer is probably some mix of promises, but I am struggling with this.
Thank you for reading!
EDIT ::
How do I set this.batches within a .then() of my call to .pullBatches()?
this.getBatches = function(){
if(!this.batches) {
console.log("Retrieved Batches");
var deferred = $q.defer();
deferred = this.pullBatches().then(function(data){
//this.batches = data; <---------------------------- HERE
});
return deferred.promise;
}else{
console.log("Didn't retrieve Batches");
}
return this.batches;
};
EDIT 2 ::
With great help from #Jahirul_Islam_Bhuiyan I fixed my issue.
this.getBatches = function(){
var deferred = $q.defer();
if(!this.batches){
console.log("Retrieved Batches");
dbInterface.pullBatches(this.getUserId()).then(function(payload){
deferred.resolve(payload.data);
service.setBatches(payload.data);
});
}else{
console.log("Didn't retrieve Batches");
deferred.resolve(this.batches);
}
return deferred.promise;
};
this.setBatches = function(batches){
this.batches = batches;
};
In Controller...
session.getBatches().then(function(data){
//console.log("getBatches.then() : " + JSON.stringify(data));
$scope.batches = data;
});
I now have a much greater understanding of promises!
Try following
this.getBatches = function(){
var deferred = $q.defer();
if(!this.batches) {
console.log("Retrieved Batches");
this.pullBatches().then(function(data){
deferred.resolve(data);
});
}else{
console.log("Didn't retrieve Batches");
deferred.resolve(this.batches);
}
var promises = [
deferred.promise
];
var promise = $q.all(promises);
return promise;
};
hope this help
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
});
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);
});