送信ボタンを押すと、ファイルの配列($scope.files
は、ユーザーが望むだけ1つのファイルにすることができます)が、私の角度関数を介して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);
}
}
問題は、var i
各ファイルの最初のforループの増分が、イベントリスナーが起動するまでに、必要なi
目的の値を超えてすでに増分してfiles[i]
おり、配列の最後の値にのみ影響することです。私は.uploadStatus
、個々のファイルの進行状況をユーザーにインタラクティブに表示する手段として使用します。そのため、の配列要素ごとに個別のイベントリスナーを用意する必要があります$scope.files
。Angularの個々の配列要素にイベントを割り当てて追跡するにはどうすればよいですか?
アップデート
2つのイベントリスナーを作り直して、少し成功しましたが、それでも奇妙な動作が発生しています。
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
関数に渡し、スプライスはそれを使用して削除する配列要素を決定していますが、必ずしも正しい要素を削除するわけではなく、配列に他の要素を残すことがよくありますそれらを削除する必要があります。