Search code examples
angularjsangularcordovaangular-servicesangular-factory

Angular service/factory - class property not updating inside the cordova file transfer


I have Angular service that does an Cordova File Transfer upload within a mobile app - it uploads a file to media server and returns an object. I am trying to pass this object to the media_response property but i'm having no luck - what I am doing wrong?

Please note - I have tried using a service and factory and still seem to get no joy - anything within the $cordovaFileTransfer upload block isn't passed to the class properties for some bizarre reason.

I am expecting to see media_response with the same output as the data variable which is an object returned from the media server but it says no response

Any idea why I'm not getting the expected response?

// Expected response

UploadService.media_response in the controller should be an object to match the console.log(data)

// Actual response

UploadService.media_response is the string 'no response'

// Upload Service

abcdServices.service('UploadService', function($http, $localStorage, $location, $q, $rootScope, $cordovaFileTransfer) {

var UploadService = function() {
    this.upload_in_progress = false;
    this.progress = 0;
    this.media_response = '';
};

UploadService.prototype.cordovaFileUpload = function (filename, url, targetPath) {
    this.upload_in_progress = true;
    this.media_response = 'no response';

    var options = {
        id: new Date() . getTime()  + filename,
        fileKey: "file",
        fileName: filename,
        chunkedMode: false,
        mimeType: "multipart/form-data",
        params : {'fileName': filename}
    };

    $cordovaFileTransfer.upload(url, targetPath, options).then(
        function(result) {
            // Success!
            var data = JSON.parse(result.response);
            console.log('file uploaded - response:', data); // ALWAYS A OBJECT
            this.media_response = 'fake response2';
            UploadService.media_response = 'fake response3';

            if (angular.isDefined(data.id)) {
                angular.forEach(data, function(value, key) {
                    // image[key] = value;
                });
                // $scope.post.linkThumbnail = false;
                // $scope.post.video = '';
            } else if (angular.isDefined(data.message)) {
                // $scope.uploadError = data.message;

            } else {

            }
        }, function(err) {

        }, function (progress) {
            // constant progress updates
            this.progress = parseInt(100 * progress.loaded / progress.total) + '%';
        }
    );

};

return new UploadService();});

// controller

UploadService.cordovaFileUpload(filename, url, targetPath, options);
console.log(UploadService); // to view in js console

Solution

  • Your this. variables are scoped to the nearest function block, not the service/factory.

    Create your variables in the root of your service/factory with either var or let.


    abcdServices.service('UploadService', function($http, $localStorage, $location, $q, $rootScope, $cordovaFileTransfer) {
    
        let upload_in_progress = false;
        let progress = 0;
        let media_response = '';
    
        var UploadService = function() {
            upload_in_progress = false;
            progress = 0;
            media_response = '';
        };
    
        UploadService.prototype.cordovaFileUpload = function (filename, url, targetPath) {
            upload_in_progress = true;
            media_response = 'no response';
    
            // Rest of your code
        };
    
    return new UploadService();});
    

    If you really need/want to use this, use the new function arrow notation, which does not create a new this-scope in the function block.

    abcdServices.service('UploadService', function(...) {
    
        this.upload_in_progress = 'test';
        this.progress = 0;
        this.media_response = '';
    
        someFunction = (param1, param2, ..) => {
            console.log(this.upload_in_progress) // 'test'
        }
    
    });