При нажатии кнопки отправки массив файлов ($scope.files
может быть всего одним файлом, столько, сколько хочет пользователь) получает через FormData
и XMLHttpRequest
в моей функции angular $scope.uploadFiles
:
$scope.uploadFiles = function() {
for (var i in $scope.files) {
var form = new FormData();
var xhr = new XMLHttpRequest;
// Additional POST variables required by the API script
form.append('destination', 'workspace://SpacesStore/' + $scope.currentFolderUUID);
form.append('contenttype', 'idocs:document');
form.append('filename', $scope.files[i].name);
form.append('filedata', $scope.files[i]);
form.append('overwrite', false);
xhr.upload.onprogress = function(e) {
// Event listener for when the file is uploading
$scope.$apply(function() {
var percentCompleted;
if (e.lengthComputable) {
percentCompleted = Math.round(e.loaded / e.total * 100);
if (percentCompleted < 1) {
// .uploadStatus will get rendered for the user via the template
$scope.files[i].uploadStatus = 'Uploading...';
} else if (percentCompleted == 100) {
$scope.files[i].uploadStatus = 'Saving...';
} else {
$scope.files[i].uploadStatus = percentCompleted + '%';
}
}
});
};
xhr.upload.onload = function(e) {
// Event listener for when the file completed uploading
$scope.$apply(function() {
$scope.files[i].uploadStatus = 'Uploaded!'
setTimeout(function() {
$scope.$apply(function() {
$scope.files[i].uploadStatus = '';
});
}, 4000);
});
};
xhr.open('POST', '/path/to/upload/script');
xhr.send(form);
}
}
Проблема заключается в том, что var i
увеличивает начальный цикл цикла для каждого файла, и к тому моменту, когда огонь прослушивает событие, i
уже увеличился за нужное значение files[i]
, но только последним в массив. Я использую .uploadStatus
как средство интерактивного отображения прогресса каждого отдельного файла для пользователя, поэтому для каждого элемента массива в $scope.files
мне понадобится отдельный прослушиватель событий. Как назначить и отслеживать события для отдельных элементов массива в Angular?
UPDATE
Я переработал два прослушивателя событий с небольшим успехом, но я все еще испытываю нечетное поведение:
xhr.upload.onprogress = (function(file) {
// Event listener for while the file is uploading
return function(e) {
$scope.$apply(function() {
var percentCompleted = Math.round(e.loaded / e.total * 100);
if (percentCompleted < 1) {
file.uploadStatus = 'Uploading...';
} else if (percentCompleted == 100) {
file.uploadStatus = 'Saving...';
} else {
file.uploadStatus = percentCompleted + '%';
}
});
}
})($scope.files[i]);
xhr.upload.onload = (function(file, index) {
// Event listener for when the file completed uploading
return function(e) {
$scope.$apply(function() {
file.uploadStatus = 'Uploaded!'
setTimeout(function() {
$scope.$apply(function() {
$scope.files.splice(index,1);
});
}, 2000);
});
}
})($scope.files[i], i);
.onprogress
, кажется, уходит без сучка и задоринки, но с небольшими изменениями, внесенными в .onload
, теперь я вижу много странного поведения с двусторонней привязкой AngularJS для своих шаблонов. для каждого элемента в массиве $scope.files
задан статус с использованием вышеупомянутого свойства .uploadStatus
. Теперь у меня есть setTimeout
сращивание элементов из массива с помощью переменной i
, которая передается в функцию самоисполнения. Как ни странно, закачки накладываются одновременно на около 6 одновременных загрузок, что должно быть проблемой на стороне сервера, но я замечаю, что по мере того, как элементы массива получают сплайсинг, ng-repeat
в шаблоне действует странно, где он будет сплайсируйте элемент, не обязательно те, которые ему нужны. Я также заметил, что часто появляются записи, которые не получают сращивания после того, как достигнут порог 2000 миллисекунд.
Это напоминает исходную проблему, когда переменная i
ненадежна при упоминании во время запуска прослушивателей событий? Теперь я передаю его анонимной самоисполняющейся функции .onload
, и сплайсинг использует ее для определения того, какой элемент массива должен удалить, но она не обязательно удаляет правильную и часто оставляет другие элементы в массив, когда он должен удалить их.