2012-11-27 16 views
43

Po naciśnięciu przycisku wysyłania, zbiór plików ($scope.files, może być tak mały, jak jeden plik, tyle, ile użytkownik chce) zostanie przesłany przez FormData i XMLHttpRequest w moim kanciastym funkcja $scope.uploadFiles:AngularJS: status śledzenia każdego przesłanego pliku jednocześnie

$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); 
    } 

} 

problemem jest to, że var i przyrosty w początkowej dla pętli dla każdego pliku, a kiedy ogień detektory zdarzeń, i już zwiększany przeszłość zamierzonej wartości files[i] potrzebne, tylko dokonania ostatniego w tablica. Używam .uploadStatus jako środka do interaktywnego pokazywania postępu każdego pojedynczego pliku użytkownikowi, w związku z czym musiałbym mieć osobne detektory zdarzeń dla każdego elementu tablicy w $scope.files. Jak przypisać i śledzić zdarzenia dla poszczególnych elementów tablicy w Angular?

UPDATE


mam przerobione dwa detektory zdarzeń, z niewielkim powodzeniem, ale ja wciąż przeżywa dziwne zachowanie:

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 wydaje się iść gładko , ale z niewielkimi zmianami wprowadzonymi do .onload, widzę teraz dziwne zachowanie z dwukierunkowym wiązaniem AngularJS dla jego szablonów. dla każdego elementu w postaci $scope.files jest podany status, z wykorzystaniem wspomnianej wcześniej właściwości .uploadStatus. Teraz mam setTimeout splice elementów z tablicy, za pomocą zmiennej i, która jest przekazywana do funkcji self-execing. Co dziwne, przesyłanie ogranicza się do około 6 równoczesnych wysyłek naraz, co musi być problemem po stronie serwera, ale zauważyłem, że gdy elementy tablicy są łączone, szablon ng-repeat działa dziwacznie w miejscu, w którym spliceruje . element, niekoniecznie taki, jaki powinien. Zauważyłem również, że często są wpisy, które nie są łączone po przekroczeniu progu 2000 milisekund.

Przypomina to pierwotny problem, w którym zmienna i jest niewiarygodna w przypadku wywoływania przez detektory zdarzeń. Teraz przekazuję go do anonimowej, samoczynnie wykonującej funkcji .onload, a splice używa jej do określenia, który element tablicy powinien usunąć, ale niekoniecznie usuwa poprawny, a często pozostawia inne elementy w tablicy, gdy powinien je usunąć.

+3

Nie jestem pewien, jak rozwiązać problem, ale to było niesamowite przykładem działa kod XHR do wysyłania plików z kątowy. Awansuj dla siebie. –

Odpowiedz

6

Przesyłane do obsługi zdarzeń funkcje index odnoszą się do indeksów w oryginalnej tablicy. Po każdym udanym połączeniu z numerem splice, tablica zmienia się, a indeksy nie wskazują już tego samego.

$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' 
4

AngularJs 1.5.5 zmienia podejście, udostępniając komunikatory zdarzeń wywołania zwrotnego dla postępu przesyłania.

Reference - 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); 
}); 
+1

Jak używać szczegółów UploadProgress w html. Używam powyższego kodu w fabryce. –

+0

eventHandlers i uploadEventHandlers nie działają od wersji 1.5.10 github.com/angular/angular.js/issues/14436 –

Powiązane problemy