Reputation: 2538
I have a issue with angular where results are returned to my controller before its actually complete even though i am using the $q.defer functionality. I have the following function in my Service
getFileInfo : function (fulfillmentId)
{
var pdfResults = [];
var jpgResults = [];
var orderDetails = {};
var deferred = $q.defer();
$http.get(appConstants.api_url + '/references/' + fulfillmentId + '/files?max=2000')
. then (function (fileResults)
{
angular.forEach(fileResults.data.entities,function(value)
{
if(value.file.extension == 'pdf')
{
pdfResults.push({files : value});
}
if(value.file.extension == 'jpg')
{
jpgResults.push({files : value});
}
});
orderDetails.jpgResults = jpgResults;
return pdfResults;
})
.then (function (pdfResults)
{
angular.forEach(pdfResults,function(value,key)
{
var fileUuid = value.files.file.file_uuid;
return $http.get(appConstants.api_url + '/resources/' + fileUuid + '/tags')
.then (function (preflightResults)
{
var deserializeJson = [];
deserializeJson.push(angular.fromJson(preflightResults.data.entities[0].resource_json));
var formatedPreflightResults = localAPI.addUIMessages(deserializeJson);
pdfResults[key].preflightResults = formatedPreflightResults;
});
});
orderDetails.pdfResults = pdfResults;
deferred.resolve(orderDetails);
});
return deferred.promise;
}
and im calling it from my controller like so:
conformAPI.getFileInfo($scope.fulfillmentId)
.then (function (results)
{
console.log(results);
console.log(results.pdfResults[0]);
console.log(results.pdfResults[0].preflightResults)
});
The problem im running into is the last console log im doing is coming up as undefined. Everything else returns results fine. The first and second console like have the preflightResults object in there but it appears that its added a bit late. I thought by using the $q.defer nothing is returned until everything is complete. Any ideas on how to fix this?
Upvotes: 1
Views: 351
Reputation: 8477
You are resolving your promise too early.
Since your first then() just returns an object, the second then() will follow immediately. So this is what the code is doing (rough pseudo-code):
$http.get().then(return first $http.get);
As soon as you have started the get of the first file, you return (return $http.get(appConstants.api_url +
...). At this point, only the very first $http.get at the top has certainly resolved. You might see the second $http.get (of the first file) resolve soon after, but you have not started any more $http.gets of any more files.
What you might have been aiming for in this code, if you remove the middle return so that all $http.gets are made, was:
$http.get().then(start all $http.gets and resolve promise);
As soon as you have looped through all files and started them with $http.get, you resolve the promise. This has the same problem -- the promise is resolved too early. All of the gets have been sent out, but you can't be sure they any have come back.
What you can do instead is:
$http.get().then(start all $http.gets and resolve promise when they have all completed);
For example, instead of a forEach on pdfResults, you can map them to an array of $http.get: filePromises = pdfResults.map(function(e) $http.get(e))
Then you would return $q.all(filePromises)
at the end where you now have deferred.resolve(orderDetails).
Upvotes: 0
Reputation: 2831
It looks like you are not waiting for the results of the "getFile" get requests. I refactored your code a bit. It might not work since I could not run it, but you should see my point.
getFileInfo: function (fulfillmentId) {
var pdfResults = [];
var jpgResults = [];
var orderDetails = {};
var deferred = $q.defer();
function getByFileId(fileUuid, preflightResults) {
return $http.get(appConstants.api_url + '/resources/' + fileUuid + '/tags')
.then(function (preflightResults) {
var deserializeJson = [];
deserializeJson.push(angular.fromJson(preflightResults.data.entities[0].resource_json));
var formatedPreflightResults = localAPI.addUIMessages(deserializeJson);
return formatedPreflightResults;
});
}
function getFiles(pdfResults) {
var subDefer = $q.defer();
var current = 0;
angular.forEach(pdfResults, function (value, key) {
current += 1;
var fileUuid = value.files.file.file_uuid;
getByFileUuid(fileUuid, preflightResults)
.then(function (results) {
pdfResults[key].preflightResults = results;
// need to know when done with all
if (pdfResults.length === current) {
subDefer.resolve(pdfResults);
}
});
});
return subDefer.promise;
}
$http.get(appConstants.api_url + '/references/' + fulfillmentId + '/files?max=2000')
.then(function (fileResults) {
angular.forEach(fileResults.data.entities, function (value) {
if (value.file.extension == 'pdf') {
pdfResults.push({ files: value });
}
if (value.file.extension == 'jpg') {
jpgResults.push({ files: value });
}
});
orderDetails.jpgResults = jpgResults;
return pdfResults;
}).then(getFiles).then(function(pdfResults) {
orderDetails.pdfResults = pdfResults;
deferred.resolve(orderDetails);
});
return deferred.promise;
}
Upvotes: 1