【问题标题】:AngularJS: tracking status of each file being uploaded simultaneouslyAngularJS:跟踪同时上传的每个文件的状态
【发布时间】:2012-11-27 19:12:00
【问题描述】:

按下提交按钮后,一组文件($scope.files,可以少至一个文件,用户想要多少就多)通过我的角度函数$scope.uploadFiles 中的FormDataXMLHttpRequest 提交:

$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 在每个文件的初始 for 循环中递增,并且在事件侦听器触发时,i 已经递增超过所需的预期 files[i] 值,仅影响最后一个大批。我使用.uploadStatus 作为向用户交互显示每个单独文件的进度的一种方式,因此我需要为$scope.files 中的每个数组元素设置单独的事件侦听器。如何为 Angular 中的单个数组元素分配和跟踪事件?

更新


我重新设计了两个事件侦听器,取得了一些成功,但我仍然遇到奇怪的行为:

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 的行为很奇怪拼接 an 元素,不一定是它应该的。我还注意到,在达到 2000 毫秒阈值后,经常有条目没有被拼接。

这让人想起最初的问题,即在整个事件侦听器的触发过程中引用变量 i 时不可靠?现在我将它传递给匿名自执行.onload 函数,并且拼接使用它来确定它应该删除的数组元素,但它不一定删除正确的元素,并且经常将其他元素留在应该删除它们的数组。

【问题讨论】:

  • 我不确定如何解决您的问题,但这是使用 Angular 进行文件上传的 XHR 代码的一个很棒的示例。为你点赞。

标签: javascript angularjs


【解决方案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 通过为上传进度提供回调事件处理程序来改变方法。

    参考 - How to track progress using eventHandlers and uploadEventHandlers in angularjs 1.5.5 with $http or $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);
    });
    

    【讨论】:

    • 如何在 html 中使用 UploadProgress 详细信息。我在工厂中使用了上面的代码。
    • eventHandlers 和 uploadEventHandlers 从 v1.5.10 github.com/angular/angular.js/issues/14436 起不起作用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    • 2018-07-15
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    • 2018-09-26
    相关资源
    最近更新 更多