En appuyant sur un bouton de soumission, un tableau de fichiers ( $scope.files
(il peut s'agir d'un seul fichier ou d'autant de fichiers que l'utilisateur le souhaite) est soumis par l'intermédiaire du site Web de la Commission européenne. FormData
y XMLHttpRequest
dans ma fonction angulaire $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);
}
}
Le problème est que var i
s'incrémente dans la boucle for initiale pour chaque fichier, et au moment où les écouteurs d'événements se déclenchent, i
a déjà été incrémenté au-delà de la date prévue files[i]
nécessaire, n'affectant que la dernière valeur du tableau. J'utilise .uploadStatus
comme un moyen de montrer de manière interactive la progression de chaque fichier individuel à l'utilisateur, je devrais donc avoir des écouteurs d'événements distincts pour chaque élément du tableau dans le fichier $scope.files
. Comment attribuer et suivre les événements pour les éléments individuels d'un tableau dans Angular ?
UPDATE
J'ai retravaillé les deux écouteurs d'événements, avec un peu de succès, mais je continue à avoir un comportement étrange :
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
semble se dérouler sans problème, mais avec quelques petites modifications apportées à .onload
Je constate maintenant un comportement étrange avec la liaison bidirectionnelle d'AngularJS pour ses modèles. for each elemnt in array $scope.files
un statut est donné, en utilisant la méthode susmentionnée .uploadStatus
propriété. Maintenant, j'ai le setTimeout
couper les éléments du tableau, via la fonction i
qui est passée dans la fonction d'auto-exécution. Assez curieusement, les téléchargements plafonnent à environ 6 téléchargements simultanés à la fois, ce doit être un problème côté serveur, mais je remarque que lorsque les éléments du tableau sont épissés, la variable ng-repeat
dans le modèle se comporte bizarrement, il va épisser un mais pas nécessairement ceux qu'il devrait. J'ai également remarqué qu'il y a souvent des entrées qui ne sont pas épissées après que le seuil de 2000 millisecondes soit atteint.
Cela rappelle le problème original où la variable i
n'est pas fiable lorsqu'il est référencé lors du déclenchement des récepteurs d'événements ? Maintenant, je le passe à la commande anonyme auto-exécutoire .onload
et le splice l'utilise pour déterminer quel élément du tableau il doit supprimer, mais il ne supprime pas nécessairement le bon élément, et laisse souvent d'autres éléments dans le tableau alors qu'il devrait les supprimer.