How to run lastTask after forEach
I have an array of images that I iterate over and upload each to a remote server. After loading the file, I use the result to get the filename and push to another array.
The problem I'm running into is that not all results are transferred to an array. I am trying to build an array with results for all uploaded images. The following code executes lastTask
until the loop ends forEach
:
/**
* Upload picture
*/
$scope.upload = function () {
var token = window.localStorage.getItem('yourTokenKey');
var defer = $q.defer();
var promises = [];
var options = {
fileKey: "image",
fileName: " test.png",
chunkedMode: true,
mimeType: "image/png",
headers: {'x-auth-token': token}
};
function lastTask() {
alert(promises);
$scope.images = [];
$scope.hide();
$scope.showAlert();
$scope.putQc();
alert('finish').then(function () {
defer.resolve();
});
}
angular.forEach($scope.images, function (image) {
$cordovaFileTransfer.upload("http://server.com/file/upload", image, options).then(function (result) {
// Success!
promises.push(result.response + '.jpg');
alert(JSON.stringify(result));
console.log("SUCCESS: " + JSON.stringify(result.response));
// Error
}, function (err) {
alert(JSON.stringify(err));
console.log("ERROR: " + JSON.stringify(err));
// constant progress updates
}, function (progress) {
$scope.show();
});
});
$q.all(promises).then(lastTask);
return defer;
};
source to share
The problem is you are not pushing promises into your promises array. You (end up) pushing normal values โโinto an array, but not before you run $q.all
on an empty or nearly empty array.
$scope.upload = function() {
var token = window.localStorage.getItem('yourTokenKey');
var promises = [];
var options = {
fileKey: "image",
fileName: " test.png",
chunkedMode: true,
mimeType: "image/png",
headers: {
'x-auth-token': token
}
};
function lastTask(results) {
alert(results);
$scope.images = [];
$scope.hide();
$scope.showAlert();
$scope.putQc();
return results; // keeping the promise chain useful
}
angular.forEach($scope.images, function(image) {
var promiseForUpload = $cordovaFileTransfer.upload("http://server.com/file/upload", image, options).then(function(result) {
console.log("SUCCESS: " + JSON.stringify(result.response));
return result.response + '.jpg'; // this will be the promised value
}, function(err) {
console.log("ERROR: " + JSON.stringify(err));
throw err; // re-throwing the error so the q.all promise is rejected
}, function(progress) {
$scope.show();
});
promises.push(promiseForUpload);
});
return $q.all(promises).then(lastTask); // returns a promise for results
};
Honestly though I would get rid of the mid-level stuff altogether:
$scope.upload = function() {
var token = window.localStorage.getItem('yourTokenKey');
var options = { /* stuff */ };
function lastTask(results) { // I wouldn't bake this into the $scope.upload, but do it as a result of calling $scope.upload (i.e. with .then).
alert(results);
$scope.images = [];
$scope.hide();
$scope.showAlert();
$scope.putQc();
return results; // keeping the promise chain useful
}
var promises = $scope.images.map(function(image){
return $cordovaFileTransfer.upload("http://server.com/file/upload", image, options);
});
return $q.all(promises).then(lastTask); // returns a promise for results
};
Finally, if this function is to return a promise, then be sure to add error handling wherever it is used (for example, with a help .catch
at the end of the chain). If this function is supposed to be the end of a promise chain (for example, it is triggered by a button click and does not hear anything), then you need to add a catch to the end $q.all(promises).then(lastTask)
. Avoid silent bugs.
source to share
If I'm right your array promises
is the problem, instead of pushing promises coming from $cordovaFileTransfer.upload
, you are calling the string result you get.
Second problem, I think you are making an anti-pattern promise , is unnecessary here $q.defer()
.
(thirdly, may be inappropriate, JSON.stringify
really unnecessary, and hopefully alert
determined by you)
I would rewrite it as:
/**
* Upload picture
*/
$scope.upload = function () {
var token = window.localStorage.getItem('yourTokenKey');
var promises = [], results; //CHANGED
var options = {
fileKey: "image",
fileName: " test.png",
chunkedMode: true,
mimeType: "image/png",
headers: {'x-auth-token': token}
};
function lastTask() {
alert(results); //CHANGED
$scope.images = [];
$scope.hide();
$scope.showAlert();
$scope.putQc();
return alert('finish'); //CHANGED
}
promises = $scope.images.map(function (image) { //CHANGED
return $cordovaFileTransfer.upload("http://server.com/file/upload", image, options).then(function (result) { //CHANGED
// Success!
results.push(result.response + '.jpg'); //CHANGED
alert(JSON.stringify(result));
console.log("SUCCESS: " + JSON.stringify(result.response));
// Error
}, function (err) {
alert(JSON.stringify(err));
console.log("ERROR: " + JSON.stringify(err));
throw err;
// constant progress updates
}, function (progress) {
$scope.show();
});
});
return $q.all(promises).then(lastTask); //CHANGED
};
source to share