Подтвердить что ты не робот

AngularJS: отслеживание каждого загружаемого файла одновременно

При нажатии кнопки отправки массив файлов ($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, и сплайсинг использует ее для определения того, какой элемент массива должен удалить, но она не обязательно удаляет правильную и часто оставляет другие элементы в массив, когда он должен удалить их.

4b9b3361

Ответ 1

index, который вы передаете обработчикам событий, ссылаются на индексы в исходном массиве. После каждого успешного вызова splice, массив изменяется, и индексы больше не указывают на одно и то же.

$scope.files = ['a.jpg', 'b.jpg', 'c.jpg'];
// $scope.files[1] = 'b.jpg'

$scope.files.splice(1,1);
// $scope.files = ['a.jpg', 'c.jpg']
// $scope.files[1] = 'c.jpg'

Ответ 2

AngularJs 1.5.5 изменяет подход, предоставляя обработчики событий обратного вызова для выполнения загрузки.

Ссылка - Как отслеживать прогресс с помощью eventHandlers и uploadEventHandlers в angularjs 1.5.5 с $http или $resource?

var uploadData = new FormData();
uploadData.append('file', obj.lfFile);
var fileData = angular.toJson({
    'FileName': obj.lfFile.name,
    'FileSize': obj.lfFile.size
});
uploadData.append('fileData', fileData)

$http({
    method: 'POST',
    url: vm.uploadPath,
    headers: {
        'Content-Type': undefined,
        'UserID': vm.folder.UserID,
        'ComputerID': vm.folder.ComputerID,
        'KeepCopyInCloud': vm.keepCopyInCloud,
        'OverWriteExistingFile': vm.overwriteExistingFile,
        'RootFileID': vm.folder.RootFileID,
        'FileName': obj.lfFile.name,
        'FileSize': obj.lfFile.size
    },
    eventHandlers: {
        progress: function(c) {
            console.log('Progress -> ' + c);
            console.log(c);
        }
    },
    uploadEventHandlers: {
        progress: function(e) {
            console.log('UploadProgress -> ' + e);
            console.log(e);
        }
    },
    data: uploadData,
    transformRequest: angular.identity
}).success(function(data) {
    console.log(data);
}).error(function(data, status) {
    console.log(data);
    console.log(status);
});