概述: 我正在使用离子框架和AngularJS创建应用程序。该应用程序有2种形式,用户可以上传图像。在第一种形式中,图像上载字段允许仅上载一个图像,而第二图像上载字段允许上载多个图像。在用户上传图像后,我在图像字段下面向用户显示预览。然后用户点击" Save",调用Web Service(定义到工厂)将图像上传到站点。 Service函数实现$ q,因此表单提交只能在上传图像后继续。这很好。
问题: 上传多个图像时,我在控制器中调用另一个辅助函数,循环(forEach)文件数据和每个文件的调用文件保存功能。但是这个辅助函数的执行并不等待forEach循环完成。这允许我获取保存文件的第一个文件详细信息,但不保留保存的文件详细信息。
以下是我用于上传文件的代码:
.controller('AppCtrl', function($q) {
// Upload single file.
$scope.fileUpload = function(fileData) {
var deferred = $q.defer();
if (angular.isUndefined(fileData) || angular.isUndefined(fileData.dataURL)) {
deferred.resolve("No new upload found.");
}
else {
var filedata = {
"file" : {
file: (fileData.dataURL).replace(/^data:image\/[A-Za-z]{3,4};base64,+/g, ''),
filename: fileData.file.name,
},
};
AuthServiceContent.uploadNewFile(filedata).then(function(response) {
deferred.resolve(response);
}, function(response) {
deferred.reject(response);
});
}
return deferred.promise;
};
// Upload multiple files.
$scope.fileUploadMultiple = function(data) {
var deferred = $q.defer();
var fileUploadStatus = [];
if (angular.isUndefined(data) || angular.isUndefined(data[0])) {
deferred.reject("No new upload found.");
}
else {
angular.forEach(data, function(fileData, index) {
$scope.fileUpload(fileData).then(function(response) {
fileUploadStatus[index] = response;
}, function(response) {
});
});
}
return (!angular.isUndefined(fileUploadStatus) ? deferred.resolve(fileUploadStatus) : deferred.reject(fileUploadStatus));
};
$scope.createContent = function(formData) {
$scope.fileUploadMultiple(formData.image).then(function(response) {
if (angular.isObject(response)) {
angular.forEach(response, function(fileData, index) {
console.log(fileData);
formData.image.und = [{'fid' : fileData.fid}];
});
console.log(formData);
}
else {
}
}, function(err) {
console.log("updates failed!!!");
});
return;
};
})
.factory('AuthServiceContent', function($q, $http, DEFAULT) {
var service_content = {
uploadNewFile: function(fileData) {
var deferred = $q.defer();
$http.post(DEFAULT.serviceURL + 'file', JSON.stringify(fileData), {
headers : {
'Content-Type': 'application/json',
'Cookie': 'cookieData',
}
})
.success(function (data, status, headers, config) {
deferred.resolve(data);
})
.error(function (data, status, headers, config) {
deferred.reject(data);
});
return deferred.promise;
}
};
return service_content;
});
我已经尝试了2天以上并发现了类似的问题,但它没有用。
更新 我通过添加额外的检入循环来实现这一点,这里是控制器中的更新功能,用于上传多个图像。
$scope.fileUploadMultiple = function(data) {
var deferred = $q.defer();
var fileUploadStatus = [];
if (angular.isUndefined(data) || angular.isUndefined(data[0])) {
deferred.reject("No new upload found.");
}
else {
var dataLength = (data.length - 1);
angular.forEach(data, function(fileData, index) {
$scope.fileUpload(fileData).then(function(response) {
fileUploadStatus[index] = response;
// Check if we are at last element. If yes, then return status
// Return deffered status on last element.
if (dataLength == index) {
deferred.resolve(fileUploadStatus);
}
}, function(response) {
// Check if we are at last element. If yes, then return status
// Return deffered status on last element.
if (dataLength == index) {
deferred.reject(fileUploadStatus);
}
});
});
}
return deferred.promise;
};
答案 0 :(得分:1)
问题在于,您只有一个承诺,并且在第一个调用上传文件返回其结果后立即解析它。
将所有承诺保存在数组中,然后尝试$ q.all:
var promises = [];
angular.forEach(data, function(fileData, index) {
promises.push($scope.fileUpload(fileData));
});
$q.all(promises).then(function(results) {
// loop through the results, one for each promise, and do what you need
})
或只返回$q.all(promises)
并让应用程序代码处理结果。
$ q.all的一个大问题是,如果任何承诺被拒绝,它只会给出错误。如果你仍然想要处理每个promise的结果,我使用$ q.allSettled的实现(我想我使用this implementation。这会返回每个promise的响应 - 成功或失败 - 带有错误消息或返回的数据,以便我可以单独处理每个承诺的结果。
希望这有帮助
答案 1 :(得分:0)
答案中的更新代码无效。如果最后一个文件是最小的,它会在上传后立即触发 resolve 。我使用的是fileIsUplaoded计数器。
$scope.fileUploadMultiple = function(data) {
var deferred = $q.defer();
var fileUploadStatus = [];
if (angular.isUndefined(data) || angular.isUndefined(data[0])) {
deferred.reject("No new upload found.");
}
else {
var uploadCount = data.length;
angular.forEach(data, function(fileData, index) {
$scope.fileUpload(fileData).then(function(response) {
// if a file is uploaded reduce the uploadCount by 1
uploadCount --;
fileUploadStatus[index] = response;
// Check if we are at last element. If yes, then return status
// Return deffered status on last element.
if (uploadCount == 0) {
deferred.resolve(fileUploadStatus);
}
}, function(response) {
// if a file is not uploaded reduce the uploadCount by 1
uploadCount --;
// Check if we are at last element. If yes, then return status
// Return deffered status on last element.
if (uploadCount == 0) {
deferred.reject(fileUploadStatus);
}
});
});
}
return deferred.promise;
};