AngularJS:跟踪同时上传的每个文件的状态

Sco*_*ott 45 javascript angularjs

在按下提交按钮,文件的数组($scope.files,可以少为一个文件,多达用户希望)通过被提交FormData,并XMLHttpRequest在我的角度功能$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);
    }

}
Run Code Online (Sandbox Code Playgroud)

问题是var i每个文件的初始for循环的增量,以及事件侦听器触发时的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);
Run Code Online (Sandbox Code Playgroud)

.onprogress似乎没有任何障碍,但随着一些小的改变.onload,我现在看到AngularJS的双向绑定模板的很多奇怪的行为.对于数组中$scope.files的每个元素,使用上述.uploadStatus属性给出状态.现在我通过传递给自执行函数setTimeouti变量来拼接数组中的元素.奇怪的是,上传现在大约每次同时上传大约6个,这必定是服务器方面的问题,但我注意到随着阵列元素的拼接,ng-repeat模板中的行为奇怪地在它将拼接一个元素,不一定是应该的元素.我还注意到,在达到2000毫秒阈值后,通常会有条目没有被拼接.

这让人联想到在i整个触发事件监听器时引用变量不可靠的原始问题?现在我将它传递给匿名自执行.onload函数,并且splice正在使用它来确定它应该删除哪个数组元素,但它不一定要删除正确的数组元素,并且经常在数组中留下其他元素应该删除它们.

abh*_*aga 6

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'
Run Code Online (Sandbox Code Playgroud)