Angular callback when multiple http are done - angularjs

How do I create 1 callback function for multiple http in angularjs. My code:
for (var i = 0; i < docs.length; i++) {
this.base64(docs[i], function(base64Img){
$http.post(urls.BASE + '/store',{doc:base64Img}).then(
function(result) {
console.log(result);
}
);
});
}
mycallback.call(); <-- this should be done when all my http.post above are done.

Use $q.all():
var deferred = $q.defer();
var httpPromises = [];
for (var i = 0; i < docs.length; i++) {
this.base64(docs[i], function(base64Img) {
httpPromises.push($http.post(urls.BASE + '/store',{doc:base64Img});
if (httpPromises.length === docs.length) {
deferred.resolve();
}
}));
}
return deferred.promise.then(function() {
return $q.all(httpPromises);
});
Note that if this.base64() returned a promise rather than taking a callback in argument, that would be simpler:
var promises = [];
for (var i = 0; i < docs.length; i++) {
promises.push(this.base64(docs[i]).then(function(base64Img) {
return $http.post(urls.BASE + '/store',{doc:base64Img});
}));
}
return $q.all(promises);
or even
return $q.all(docs.map(function(doc) {
return this.base64(doc).then(function(base64Img) {
return $http.post(urls.BASE + '/store',{doc:base64Img});
});
});

Okay so I created a HttpInterceptor Service for this so every time a request starts it checks if there are more requests within a certain timelimit and then after all of those requests responded It broadcasts "all requests done".
For that to work I embeded my Intercepter like this in my App.js
.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
})
And my service looks like this basicly there is a variable numloadings which counts the requests up and when there is a respones it counts them down when it reaches 0 all requests went through
.factory('httpInterceptor', ['$q', '$rootScope', '$filter', function ($q, $rootScope, $filter) {
var canceller = $q.defer();
var numLoadings = 0;
var serialRequests = false;
var timeO;
var time1;
var Cntr1 = 0;
var Cntr2 = 0;
var currentReqUrl;
$rootScope.broadcast = true;
var loadingbar = { loading: "<progress value='?' max='10'></progress>" };
var loadingspinner = { loading: '<ion-spinner icon="crescent"></ion-spinner>' };
return {
request: function (config) {
config.timeout = 200000;
numLoadings++;
if (serialRequests == false) {
$rootScope.$broadcast("open_requests", loadingspinner);
} else {
clearTimeout(timeO);
}
}
return config || $q.when(config)
},
response: function (response) {
serialRequests = true;
numLoadings--;
timeO = setTimeout(function () {
serialRequests = false
if ((numLoadings) === 0) {
$rootScope.$broadcast("all_requests_done");
}
});
}
return response || $q.when(response);
},
responseError: function (response) {
serialRequests = true;
numLoadings--;
timeO = setTimeout(function () {
serialRequests = false
if ((numLoadings) === 0) {
$rootScope.$broadcast("all_requests_done");
}
});
}
return $q.reject(response);
}
};

Related

angular service modal not closing properly & calling multiple times

Mentioned on the github repository #225 of angular-service-modal
But i don't have a $on on $rootScope, so that shouldn't be the problem.
(also included code below)
My modal is getting called multiple times on close/hiding. Eg. [http://beta.belgianbrewed.com/en/product/budweiser-24x30cl](Example page)
The file in question can be found on /assets/angular/controllers/ShopActionController.js
Any thoughts where the problem could be?
The code calls: showPopup(ProductId,'BuyImmediate') in ShopActionController.js
app.controller('ShopActionDialogController', ['$scope', 'CurrentProduct', function ($scope, CurrentProduct) {
$scope.CurrentProduct = CurrentProduct;
console.log("Dialog called and ...");
console.log(CurrentProduct);
//modal.element.modal();
//modal.close.then(function (result) {
// $scope.message = result ? "You said Yes" : "You said No";
//});
}]);
app.controller('ShopActionController', ['$rootScope', '$scope', '$injector', '$http', '$timeout', 'ModalService', 'EndpointService', 'ImageResizeService', 'hotkeys',
function ($rootScope, $scope, $injector, $http, $timeout, ModalService, EndpointService, ImageResizeService, hotkeys) {
$scope.Resize = ImageResizeService;
$scope.Amount;
$scope.InitAmount;
$scope.ProductId;
$scope.ProductVariantId;
$scope.OrderLineId;
$scope.isLoading = false;
$scope.isShown = true;
//$scope.addedToCart = false; //new - not implemented
$scope.inCartAmount = 0; //new - not implemented
$scope.inWishList = false;
$scope.Change = function (Amount) {
$scope.Amount += Amount;
}
$scope.showPopup = function (ProductId,action) {
EndpointService.searchProducts(undefined, 0, 1, ProductId).then(function (response) {
ModalService.showModal({
templateUrl: "ProductPopup.html",
controller: "ShopActionDialogController",
inputs: {
CurrentProduct: response.data[0]
}
}).then(function (modal) {
// The modal object has the element built, if this is a bootstrap modal
// you can call 'modal' to show it, if it's a custom modal just show or hide
// it as you need to.
// console.log("test");
modal.element.modal();
var args = {
Amount: $scope.Amount,
ProductId: response.data[0].Id,
ProductVariantId: response.data[0].ProductVariantId,
OrderLineId: undefined,
InitAmount : $scope.InitAmount
};
if (action != undefined) {
args.Action = action;
}
$rootScope.$broadcast('init', args);
$scope.Amount = $scope.InitAmount;
modal.element.on('hidden.bs.modal', function (e) {
// $scope.Amount = $scope.InitAmount;
console.log("hidden");
modal.element.remove();
// close(result, 200);
});
modal.close.then(function (result) {
// console.log("close");
$scope.Amount = $scope.InitAmount;
modal.element.remove();
// close(result, 200);
//ModalService.closeModals();
// $scope.message = result ? "You said Yes" : "You said No";
});
});
});
}
$scope.CurrentProduct;// = CurrentProduct;
$scope.initiated = false;
var initListener = $scope.$on('init', function (event,args) {
if (!$scope.initiated) {
$scope.Amount = args.Amount;
$scope.InitAmount = args.InitAmount;
$scope.ProductId = args.ProductId;
$scope.ProductVariantId = args.ProductVariantId;
$scope.OrderLineId = args.OrderLineId;
switch (args.Action)
{
case 'BuyImmediate':
$scope.AddToCart();
break;
case 'View':
break;
}
}
});
$scope.$on('$destroy', function () {
console.log("killing this scope");
initListener();
});
$scope.init = function (Amount, ProductId, ProductVariantId, OrderLineId) {
$scope.initiated = true;
$scope.Amount = Amount;
$scope.InitAmount = Amount;
$scope.ProductId = ProductId;
$scope.ProductVariantId = ProductVariantId;
$scope.OrderLineId = OrderLineId;
}
$scope.getSpecification = function (Product,SpecificationId, SpecificationName) {
var Spec = undefined;
angular.forEach(Product.Specifications, function (elem, i) {
if (elem.SpecificationCandidate.SpecificationId == SpecificationId ||
elem.SpecificationCandidate.Specification.Name == SpecificationName) {
Spec = elem.SpecificationCandidate;
}
});
return Spec;
}
$scope.isAddedInCart = function () {
return $scope.OrderLineId != undefined;
}
$scope.PriceInclusive = function (orderline) {
return orderline.Amount * orderline.Product.Price * 1.21;
}
$scope.PriceExclusive = function (orderline) {
return orderline.Amount * orderline.Product.Price;
}
$scope.bindKeys = function () {
hotkeys.add({
combo: '+',
description: 'Add 1 to ammount',
callback: function () {
$scope.Amount += 1;
}
});
hotkeys.add({
combo: '-',
description: 'Substract 1 from ammount',
callback: function () {
if ($scope.Amount > 0) {
$scope.Amount -= 1;
}
}
});
}
$scope.IncrementWith = function (Amount) {
var newAmount = $scope.Amount + Amount;
if (newAmount >= 0) {
$scope.Amount = newAmount;
}
}
$scope.ChangeSortBy = function (SortBy) {
console.log("Changing Sort By");
}
$scope.ChangePageSize = function (PageSize) {
console.log("Changing PageSize");
}
$scope.GetCart = function () {
return EndpointService.orderlines;
}
$scope.RemoveOrderLine = function ($event) {
$scope.isLoading = true;
EndpointService.removeOrderLine($scope.OrderLineId)
.then(function (response) {
EndpointService.orderlines = response.data;
$rootScope.$broadcast('DeleteOrderLine', { OrderLineId: $scope.OrderLineId });
$scope.isLoading = false;
$scope.isShown = false;
});
$event.preventDefault();
return false;
}
$scope.AddToWishlist = function () {
//AddToWishlist
EndpointService.addToWishList($scope.ProductId)
.then(function (response) {
//return true;
$scope.inWishList = true;
});
return false;
}
$scope.RemoveFromWishlist = function () {
EndpointService.removeFromWishList($scope.ProductId)
.then(function (response) {
//return true;
$scope.isShown = false;
});
return false;
}
$scope.PrepareAddOrderLineRequest = function (onlyBulk) {
if (!onlyBulk || (onlyBulk && $scope.InitAmount == 0 && $scope.InitAmount < $scope.Amount)) {
var request = EndpointService.UpdateAmountRequest;
request.OrderLineId = $scope.OrderLineId;
request.Amount = $scope.Amount;
request.ProductId = $scope.ProductId;
return request;
} else {
return undefined;
}
}
$scope.FocusAmountInput = function () {
if ($scope.Amount == $scope.InitAmount) {
$scope.Amount = "";
}
}
$scope.LeaveAmountInput = function () {
if ($scope.Amount == "") {
$scope.Amount = $scope.InitAmount;
}
}
$scope.$on("BroadCastBulkOrders", function () {
var request = $scope.PrepareAddOrderLineRequest(true);
if (request != undefined) {
$rootScope.$broadcast("AddBulkOrder", request);
$scope.Amount = $scope.InitAmount;
}
});
$scope.AddToCart = function () {
$scope.isLoading = true;
var request = $scope.PrepareAddOrderLineRequest(false);
EndpointService.updateAmount(request)
.then(function (response) {
EndpointService.orderlines = response.data;
$rootScope.$broadcast('BasketChanged');
angular.forEach(response.data, function (elem, i) {
if (elem.ProductId == $scope.ProductId) {
$scope.OrderLineId = elem.Id;
$scope.inCartAmount = elem.Amount;
}
});
$scope.Amount = $scope.InitAmount;
$scope.isLoading = false;
});
return false;
}
$scope.UpdateOrderLine = function () {
//$emit required values
$scope.isLoading = true;
var request = $scope.PrepareAddOrderLineRequest(false);
request.isFixed = true;
EndpointService.updateAmount(request)//$scope.OrderLineId, $scope.ProductId, $scope.Amount, true)
.then(function (response) {
angular.forEach(response.data, function (elem, i) {
if (elem.Id == $scope.OrderLineId) {
$rootScope.$broadcast('ChangeAmount', { OrderLineId: $scope.OrderLineId, Amount: $scope.Amount });
}
});
$scope.isLoading = false;
});
return false;
}
}]);
The service
app.service('EndpointService', ['$http', '$q', function ($http, $q) {
this.orderlines = new Array();
//search for products, standard paging included
this.searchProducts = function (searchTerm, page, pageSize, productId) {
var endPoint = "/api/Endpoint/SearchProducts?$expand=Tags,Specifications($expand=SpecificationCandidate($expand=Specification)),CoverPhoto";
if (searchTerm != undefined && searchTerm.length > 0) {
endPoint = endPoint + "&$filter=indexof(Title,'" + searchTerm + "') gt -1"; //make a var
} else if (productId !== undefined) {
{
endPoint = endPoint + "&$filter=Id eq " + productId + " "; //make a var
}
//endPoint = endPoint + "&$filter=";
}
endPoint = endPoint + "&$skip=0&$top=" + pageSize;
return $http.get(endPoint);
//.then(function (response) {
// //console.log(response.data);
// return response.data;
//})
}
// this.ShippingCost = $q.defer();
this.ShippingCost = new Object();
this.calculateShipping = function (address, shippingMethodId) {
if (address == undefined) {
return this.ShippingCost;
} else {
//https://appendto.com/2016/02/working-promises-angularjs-services/
//var deferred = $q.defer();
var endPoint = "/api/Endpoint/CalculateShippingCost?timestamp=" + Date.now();
return $http({
url: endPoint,
method: "GET",
params: {
DeliveryAddress: address,
ShippingMethodId: shippingMethodId,
timestamp: Date.now()
}
})
}
}
this.getOrderLines = function () {
var endPoint = "/api/Endpoint/GetOrder";
return $http({
url: endPoint,
method: "GET",
params: {
timestamp : Date.now()
}
})
.then(function (response) {
this.orderlines = response.data;
return this.orderlines;
});
}
this.removeOrderLine = function (OrderLineId) {
var endPoint = "/api/Endpoint/RemoveOrderLine";
return $http({
url: endPoint,
method: "POST",
params: {
OrderLineId: OrderLineId
}
});
}
this.addToWishList = function (ProductId) {
var endPoint = "/api/Endpoint/AddToWishlist";
return $http({
url: endPoint + "?ProductId=" + ProductId,
method: "GET"
});
}
this.removeFromWishList = function (ProductId) {
var endPoint = "/api/Endpoint/RemoveFromWishlist";
return $http({
url: endPoint + "?ProductId=" + ProductId,
method: "GET"
});
}
this.UpdateAmountRequest = {
ProductId: "",
Amount: 0,
OrderLineId: "",
isFixed : false
}
this.bulkUpdateAmount = function (request) {
var endPoint = "/api/Endpoint/BulkAddOrderLines";
return $http({
url: endPoint,
method: "POST",
headers: {
'Content-Type': "application/json"
},
data: request
});
}
this.updateAmount = function (request){//OrderLineId,ProductId, Amount, isFixed) {
var endPoint = "/api/Endpoint/AddOrderLine?timestamp="+ Date.now();
//console.log("hey, changing the amount " + Amount + " for product id " + ProductId + " are you? :) ");
return $http({
url: endPoint,
method: "POST",
headers: {
'Content-Type': "application/json"
},
data: request
});
}
}]);
You need to add your bootstrap modal hidden listener to the dialog controller context.
app.controller('ShopActionDialogController', ['$scope', '$element', 'CurrentProduct', 'close', function ($scope, $element, CurrentProduct, close) {
$scope.CurrentProduct = CurrentProduct;
console.log("Dialog called and ...");
console.log(CurrentProduct);
//modal.element.modal();
//modal.close.then(function (result) {
// $scope.message = result ? "You said Yes" : "You said No";
//});
//listen for when the modal is dismissed and resolve the ModalService Close promise
$element.on('hidden.bs.modal', function (e) {
close({
currentProduct: CurrentProduct
}, 200); // close, but give 200ms for bootstrap to animate
});
}]);
Note that $element and close were added to the controller dependencies.

Then is not a function error in angularjs

I have simple function which returns employee data. But getting then is not a function error how to retrieve response from function
function getdata(criteria) {
return angularService.GetData(criteria, $scope.year, $scope.selectedYearType.name);
}
Which is called in below function
$scope.GetEmployeeData = function (criteria) {
$scope.searchMethod = getdata;
$scope.searchMethod().then(function (response) {----------> Error here
var totalEmployeeAmount = 0;
for (var i = 0; i < response.data.results.length; i++) {
var summaryData = response.data.results[i];
totalEmployeeAmount += (summaryData.totalEmployeeAmount);
}
return response
}, function (response) {
// This is to see if has any error
//console.log(response);
});
}
My angular service
function getData(criteria, year, yearType) {
var url = apiService.ApiUrl + "/Employees/EmployeeHistory/GetData/" + year + "/" + yearType;
return apiService.DeferredPost(url, criteria);}
Deferred Post Method
function deferredPost(url, params) {
var deferred = $q.defer();
$http.post(url, params)
.then(function (data) {
deferred.resolve(data);
}, function (resp) {
deferred.reject(resp);
}).catch(function (data) {
deferred.reject(data);
});
return deferred.promise;
}
API
var api = {
DeferredPost: deferredPost
};
return api;
Should be calling .then on searchMethod instead of searchMethod() - assuming getdata returns a promise as you can't call .then on a function that doesn't return a promise. Also I'm guessing you should be passing in the criteria as a parameter to getdata:
$scope.GetEmployeeData = function (criteria) {
$scope.searchMethod = getdata;
$scope.searchMethod.then(function (response) {
var totalEmployeeAmount = 0;
for (var i = 0; i < response.data.results.length; i++) {
var summaryData = response.data.results[i];
totalEmployeeAmount += (summaryData.totalEmployeeAmount);
}
return response
}, function (response) {
// This is to see if has any error
//console.log(response);
});
}
As #William Hampshire said, you should be using $scope.searchMethod.then(function ... ) instead of $scope.searchMethod().then(function ... )
$scope.GetEmployeeData = function (criteria) {
$scope.searchMethod = getdata(criteria);
$scope.searchMethod.then(function (response) {
var totalEmployeeAmount = 0;
for (var i = 0; i < response.data.results.length; i++) {
var summaryData = response.data.results[i];
totalEmployeeAmount += (summaryData.totalEmployeeAmount);
}
return response
}, function (response) {
// This is to see if has any error
//console.log(response);
});
}
The reason why your code is still failing is that you have a typo in your service name.
function getdata(criteria) {
return angularService.GetData(criteria, $scope.year, $scope.selectedYearType.name);
}
It should be GetData instead of getData.
function GetData(criteria, year, yearType) {
var url = apiService.ApiUrl + "/Employees/EmployeeHistory/GetData/" + year + "/" + yearType;
return apiService.DeferredPost(url, criteria);}

angular multiple http looping request with time delay

I have an ID array contains with 50+ id.
var ids = [
'3407197',
'0632706',
'18275',
...,
...
]
I want to send angular HTTP get request with a loop. Each iteration will delay 10 sec delay. When all the request complete it will notify that request are completed.
I have tried with this code but It executes at once not delaying.
function collector(i){
setTimeout(function() {
return $http.get('http://example.com/' + ids[i])
.success(function(data) {
})
.error(function(err) {
})
},10000);
}
$scope.getAllData = function() {
var promises = [];
for (var i = 0; i < ids.length; i++) {
promises.push(collector(i));
}
return $q.all(promises);
}
$scope.getAllData ().then(function(data) {
$scope.debug = 'done';
});
Try with $timeout:
function getRequest(id) {
return $http.get('http://example.com/' + id)
.success(function (data) {})
.error(function (err) {});
}
var promise = $timeout();
ids.forEach(function(id) {
promise = promise.then(function() {
getRequest(id);
return $timeout(10000);
});
});
// not sure if this works
promise.then(function() {
$scope.debug = 'done';
});

AngularJS Multiple GET requests, only first returning correctly

I have the following in my controller:
ApiRequest.get('locations').then(function(locations) {
$scope.locations = locations.locations;
});
ApiRequest.get('sublocations').then(function(sublocations) {
$scope.sublocations = sublocations.sublocations;
});
ApiRequest.get('varieties').then(function (varieties) {
$scope.varieties = varieties.varieties;
});
ApiRequest.get('tasks').then(function(tasks) {
$scope.tasks = tasks.tasks;
});
ApiRequest.get('customers').then(function(customers) {
$scope.customers = customers.customers;
});
ApiRequest.get('batches').then(function(batches) {
$scope.batches = batches.batches;
$ionicLoading.hide();
});
The data from each of these requests goes on to poplate select boxes in a form.
Here is my APIRequest service:
return {
get: function(entity) {
if($rootScope.online == false) {
var data = {};
data = JSON.parse(localStorage.getItem('data-' + entity));
console.log(data);
deferred.resolve(data);
} else {
$http.get($rootScope.baseUrl + entity).success(function(data) {
deferred.resolve(data);
})
}
return deferred.promise;
},
}
It would appear that for some reason the results aren't getting back from the service on time to display them in the view.
Is this something to do with the way I am handling the promise?
At first look, you declared the promise with $q outside your function as global (because I don't see inside). Try this one:
get: function(entity) {
var deferred = $q.defer();
if($rootScope.online == false) {
var data = {};
data = JSON.parse(localStorage.getItem('data-' + entity));
console.log(data);
deferred.resolve(data);
} else {
$http.get($rootScope.baseUrl + entity).success(function(data) {
deferred.resolve(data);
})
}
return deferred.promise;
},
your current implementation has little to no error handling and is executing multiple API requests in parallel; I would recommend chaining the promises.
ApiRequest.get('locations').then(function(locations) {
$scope.locations = locations.locations;
return ApiRequest.get('sublocations');
}).then(function(sublocations) {
$scope.sublocations = sublocations.sublocations;
return ApiRequest.get('varieties')
}).then(function (varieties) {
$scope.varieties = varieties.varieties;
return ApiRequest.get('tasks')
}).then(function(tasks) {
$scope.tasks = tasks.tasks;
return ApiRequest.get('customers')
}).then(function(customers) {
$scope.customers = customers.customers;
return ApiRequest.get('batches')
}).then(function(batches) {
$scope.batches = batches.batches;
$ionicLoading.hide();
}, function(_error) {
$ionicLoading.hide();
console.log(_error);
});
and then your service can be simplified; the $http client returns a promise and using $q.when can return a promise also
get: function(entity) {
if($rootScope.online == false) {
var data = {};
data = JSON.parse(localStorage.getItem('data-' + entity));
console.log(data);
$q.when(data);
} else {
return $http.get($rootScope.baseUrl + entity)
}
},

AngularJS/Ionic Service Factory Cache

I'm trying to "cacheify" my angular service factory. I want it to use the cache to hit the URL only the first time the page is loaded. Then when I browse to my detail page (findById) I want to use the cache. Does this make sense?
Below is what I have right now but I can't figure out a solid way to handle this async. My controller is calling into the service.
angular.module('myapp.services', [])
.factory('myservice', function ($http, $q, $cacheFactory) {
var url = '//myurl.com/getawesomeJSON';
return {
findAll: function () {
var $httpDefaultCache = $cacheFactory.get('$http');
var data = $httpDefaultCache.get(url);
if (data == null) {
data = $http.get(url, { cache: true });
}
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
},
findById: function (id) {
var data = angular.fromJson($cacheFactory.get('$http').get(url)[1]);
for (var i = 0; i < data.length; i++) {
if (data[i].Id === parseInt(id)) {
var deferred = $q.defer();
deferred.resolve(data[i]);
return deferred.promise;
}
}
}
}
});
I haven't tested this since you didn't provide a plunker, but the following should set you in the right direction. You need to make use of promise chaining.
angular.module('myapp.services', [])
.factory('myservice', function ($http, $q, $cacheFactory) {
var url = '//myurl.com/getawesomeJSON';
return {
findAll: function () {
var $httpDefaultCache = $cacheFactory.get('$http');
var deferred = $q.defer();
var data = $httpDefaultCache.get(url);
if (!data) {
$http.get(url, { cache: true }).then(function(result){
deferred.resolve(result);
});
} else {
deferred.resolve(data);
}
return deferred.promise;
},
findById: function (id) {
return this.findAll().then(function(data) {
for (var i = 0; i < data.length; i++) {
if (data[i].Id === parseInt(id)) {
return data[i];
}
}
return $q.reject('Not found'); // id not found
});
}
}
});

Resources