6

Can anyone help me with some Angular promises? I have the following functions that should take in an array of file objects, iterate over them, and upload each one. During each iteration, a promise object is pushed to an array of promises. Within my upload function I have a cycle function with a .then() attached, which should not be called until all the promise objects have resolved. I think my code looks correct, but it's not working right. The images upload, but cycle(files).then() is being called immediately, rather than once the promises array resolves.

function upload(files) {
    var uploadCount = files.length;
    function cycle(files) {
        var promises = [];
        for (var i = 0; i < files.length; i++) {
            var deferred = $q.defer();
            promises.push(deferred);
            var file = files[i];
            Upload.upload({
                url: '/photos.json',
                file: file
            }).success(function(){
                $scope.progressCurrentCount += 1;
                deferred.resolve();
            });
        };
        return $q.all(promises);
    };

    cycle(files).then(function(result) {
        if(uploadCount > 1) {
            $scope.lastAction = 'uploaded ' + uploadCount + ' photos';
        } else {
            $scope.lastAction = 'uploaded ' + uploadCount + ' photo';
        }
        $scope.showSuccessModal = true;
        $scope.uploading = false;
        $scope.failedUploads = [];
        $scope.newPhotos = {
            token: $scope.token,
            files: undefined
        };
        photoUploadBtn.removeClass('disabled');
    })
};

Final working code*

Rather than setting var deferred = $q.defer(); pushing deferred.promise into the promises array, and then resolving deferred in my .success() callback, which wasn't working, I just push my Upload.upload() function without the .success() callback into promises, and then pass that to $q.all(), which does all the lifting.

function upload(files) {
    var uploadCount = files.length;
    function cycle(files) {
        var promises = [];
        for (var i = 0; i < files.length; i++) {
            var file = files[i];
            var promise = Upload.upload({
                url: '/photos.json',
                file: file
            });
            promises.push(promise);
        };
        return $q.all(promises);
    };

    cycle(files).then(function(result) {
        if(uploadCount > 1) {
            $scope.lastAction = 'uploaded ' + uploadCount + ' photos';
        } else {
            $scope.lastAction = 'uploaded ' + uploadCount + ' photo';
        };
        $scope.showSuccessModal = true;
        $scope.uploading = false;
        $scope.failedUploads = [];
        $scope.newPhotos = {
            token: $scope.token,
            files: undefined
        };
        photoUploadBtn.removeClass('disabled');
        getPhotos(q);
    })
};

1 Answer 1

11

You must push a promise, not a deferred, to the promises array:

promises.push(deferred.promise);

It helps if you think about it like this:

  • the promise is a read-only object you want to return to the consumers
  • deferred is the modifier of that read-only promise and you want to keep it for yourself
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, that was most of the solution I needed! I also came upon this article, which made me realize that I should approach things slightly differently. I'll put my final code in my post above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.