简体   繁体   中英

Angular: cannot read property 'then' of undefined

I have a service upload imageto amazon s3 after i sign it with my own backend using cordova file-transfer plugin. I call this service after taking a picture using cordova camera plugin to upload the taken picture to the s3 bucket . The app sign correctly with my own backend but when it trigger the function upload i get the error i defined in the title. This is the service that it call an end point in my backend to sign the file and then upload the image to amazon s3 :

//Image upload Service
.factory('S3Uploader', function($q, $window, $http, $ionicPopup, API_URL) {

    var signingURI = API_URL + "s3signing";

    function upload(imageURI, fileName) {
        document.addEventListener('deviceready', function() {
            console.log('Uploading ' + fileName + ' to S3');

            var deferred = $q.defer(),
                ft = new FileTransfer(),
                options = new FileUploadOptions();

            options.fileKey = "file";
            options.fileName = fileName;
            options.mimeType = "image/jpeg";
            options.chunkedMode = false;

            console.log('Requesting signed doc ' + signingURI);
            $http.post(signingURI, {
                "fileName": fileName
            })
                .success(function(data) {
                    console.log('Got signed doc: ' + JSON.stringify(data));
                    options.params = {
                        "auth": true,
                        "key": fileName,
                        "AWSAccessKeyId": data.awsKey,
                        "acl": "public-read",
                        "policy": data.policy,
                        "signature": data.signature,
                        "Content-Type": "image/jpeg"
                    };

                    ft.upload(imageURI, "https://" + data.bucket + ".s3.amazonaws.com/",
                        function(e) {
                            console.log("Upload succeeded");
                            console.log(JSON.stringify(e));
                            deferred.resolve(e);
                            $ionicPopup.alert({
                                title: 'great',
                                content: 'The image upload to amazon success'
                            });
                        },
                        function(e) {
                            deferred.reject(e);
                            $ionicPopup.alert({
                                title: 'Oops',
                                content: 'The image upload failed to amazon'
                            });
                        }, options);

                })
                .error(function(data, status, headers, config) {
                    console.log(JSON.stringify(data));
                    console.log(status);
                    $ionicPopup.alert({
                        title: 'Oops',
                        content: 'The image upload failed to sign with node'
                    });
                });

            return deferred.promise;

        }, false); //device ready

    }

    return {
        upload: upload
    }

})

and here is the controller code where am calling the camera plugin and in the success of taking the picture am calling the upload function from the S3Uploader service:

.controller('newItemCtrl', function($scope, $http, $ionicPopup, $timeout, $cordovaCamera, API_URL, me, S3Uploader) {
$scope.selectPicture = function() {
        document.addEventListener('deviceready', function() {

            var options = {
                destinationType: Camera.DestinationType.FILE_URI,
                sourceType: Camera.PictureSourceType.CAMERA,
                allowEdit: true,
                encodingType: Camera.EncodingType.JPEG,
                targetWidth: 300,
                targetHeight: 300,
            };
            $cordovaCamera.getPicture(options).then(function(imageURI) {
                $scope.imageSrc = imageURI;
                // upload to Amazon s3 bucket
                var fileName = new Date().getTime() + ".jpg";
                S3Uploader.upload(imageURI, fileName).then(function() {
                    alert("upload to S3 successed");
                });
            }, function(err) {
                alert(err);
            });

        }, false); // device ready
    }; // Select picture
}) 

i get the erorr in this line of the controller:

S3Uploader.upload(imageURI, fileName).then(function() {

it's also important to mention am using crosswalk with my ionic app.

Your current implementation of S3Uploader.upload does not return a promise, it returns nothing. Move your declaration and return of the promise to directly inside the S3Uploader.upload function and not nested inside the document.addEventListener code.

Change your code to something like:

.factory('S3Uploader', function($q, $window, $http, $ionicPopup, API_URL) {

    var signingURI = API_URL + "s3signing";

    function upload(imageURI, fileName) {
        var deferred = $q.defer()
        document.addEventListener('deviceready', function() {
            // Removed for brevity
        }, false);
        return deferred.promise;
    }

    return {
        upload: upload
    }

})

You are creating and returning your deferred object and it's promise from an event listener. Not the upload factory method.

Something along these lines is what you need:

.factory('S3Uploader', function($q) {

    function upload() {
        var deferred = $q.defer();

        // listener logic

        return deferred.promise;
    }

    return {
        upload : upload
    }
});

You will have problems with this, as you will want a new deferred object for each time the listener is fired. Adding a listener to a factory method to perform something seems like a bad pattern to me. The event should wrap the invocation of the factory method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM