Reputation: 97
I have a factory method which looks like below:
angular.module('GridSamplesApp')
.factory('registerPostFactory', function($resource, $q, WebRequest) {
var getMessage = function(Upddata, token, dataurl)
{
var deferred = $q.defer();
var settings = {
data: Upddata,
headers: {
'Content-Type': 'application/JSON',
'x-csrf-token' : token
},
method: 'POST',
url: dataurl,
withCredentials: true
};
WebRequest.requestRaw(settings).then(
function(response) {
// data from app sec
var msg = response;
deferred.resolve(msg);
},
function(error) {
console.log('Error retrieving message', error);
deferred.reject('Error retrieving message', error);
});
return deferred.promise;
};
return {
getMessage: getMessage
};
});
I have a controller which looks like
$scope.getLogs = function()
{
$.each($scope.modifiedSN, function(i, e) {
if ($.inArray(e, result) == -1) result.push(e);
});
$scope.inputs.push({SN:'', Key:'', status:'', log:''});
for(var i=0; i<result.length; i++)
{
var j = result[i];
if ($scope.data[j].SerialNumber !== "")
{
var Upddata = {};
Upddata['IConvRuleFlg'] = '';
Upddata['SrNum'] = $scope.data[j].SerialNumber;
Upddata['LvEmailId'] = '[email protected]';
Upddata['WKey'] = $scope.data[j].WtyKey;
registerPostFactory.getMessage(Upddata, $scope.token, dataurl).then(
function(response) {
$scope.msg = response.headers["custommessage"];
$scope.data[j].AutolinkErrorlog = $scope.msg;
$scope.inputs.push({SN: $scope.data[j].SerialNumber, Key: $scope.data[j].WtyKey, status: response.headers["msgtype"], log: $scope.msg});
},
function(error) {
console.log('Error reading msg: ', error);
}
);
}
}
};
The issue with this is that it only takes the last element in the array since it is an asynchronous call and the loop will not wait for the response, I tried using $q.all()
but could not figure out how to implement this, can anyone please help?
Upvotes: 1
Views: 944
Reputation: 25044
From what I understand, your factory works ok, and like @RaviMone said, it is with the usage of async callback code within for loop, you ll be surprised how often beginners fall into that trap. Also, I see a $scope.msg
, not sure where it comes from and how it works, but due to async and parallel nature of your calls, it might be display wrong values for various calls, if it changes per call, you should think about serializing your call.
A cleaner way to write $scope.getLogs
might be( I have reduced the usage of jQuery, used ES5 stuff, if you have to support legacy systems, you can use this ):
$scope.getLogs = function(){
var result = [] // again not sure where the result comes from, so initizing it here, else you can append filtered array to the previous set
$scope.modifiedSN.forEach(function(value) {
if (result.indexOf(value) < 0) result.push(e);
});
$scope.inputs.push({SN:'', Key:'', status:'', log:''});
var promises = result.map(function(val){
return $scope.data[val];
}).filter(function(val){
return val && val.SerialNumber !== ""; // first check if $scope.data[j] exists
}).map(function(val){
return registerPostFactory.getMessage({
IConvRuleFlg: '',
LvEmailId: '',
WKey: val.WtyKey,
SrNum: val.SerialNumber
}).then(function(response){
$scope.msg = response.headers["custommessage"];
val.AutolinkErrorlog = $scope.msg;
$scope.inputs.push({SN: val.SerialNumber, Key: val.WtyKey, status: response.headers["msgtype"], log: $scope.msg});
}).catch(function(e){
console.log('Error reading msg: ', e);
});
});
$q.all(promises)
.then(function(resArray){
console.log('get all logs...');
}).catch(function(e){
console.log('some error: ', e);
});
};
Edit:
if you want them done in sequence:
$scope.getLogs = function(){
var result = [] // again not sure where the result comes from, so initizing it here, else you can append filtered array to the previous set
, serialPromise = $q.when(1); // just initializing a promise.
$scope.modifiedSN.forEach(function(value) {
if (result.indexOf(value) < 0) result.push(e);
});
$scope.inputs.push({SN:'', Key:'', status:'', log:''});
result.map(function(val){
return $scope.data[val];
}).filter(function(val){
return val && val.SerialNumber !== ""; // first check if $scope.data[j] exists
}).forEach(function(val){
var datum = {
IConvRuleFlg: '',
LvEmailId: '',
WKey: val.WtyKey,
SrNum: val.SerialNumber
};
serialPromise = serialPromise.then(function(){ // adding a new promise to the chain.
return registerPostFactory.getMessage(datum);
}).then(function(response){
$scope.msg = response.headers["custommessage"];
val.AutolinkErrorlog = $scope.msg;
$scope.inputs.push({SN: val.SerialNumber, Key: val.WtyKey, status: response.headers["msgtype"], log: $scope.msg});
}).catch(function(e){
console.log('Error reading msg: ', e);
});
});
serialPromise.then(function(){
console.log('got all logs...');
}).catch(function(e){
console.log('some error: ', e);
});
};
Upvotes: 1
Reputation: 5485
Here you have to use closure, I have modified your code,
(function(data) {
//console.log(data) //You can notice here, you are getting all individual loop objects
var Upddata = {};
Upddata['IConvRuleFlg'] = '';
Upddata['SrNum'] = data.SerialNumber;
Upddata['LvEmailId'] = '[email protected]';
Upddata['WKey'] = data.WtyKey;
registerPostFactory.getMessage(Upddata, $scope.token, dataurl).then(
function(response) {
$scope.msg = response.headers["custommessage"];
$scope.data[j].AutolinkErrorlog = $scope.msg;
$scope.inputs.push({
SN: data.SerialNumber,
Key: data.WtyKey,
status: response.headers["msgtype"],
log: $scope.msg
});
},
function(error) {
console.log('Error reading msg: ', error);
}
);
})($scope.data[j]);
Upvotes: 0