Niall O'Brien
Niall O'Brien

Reputation: 182

Variable scope within Angular factory promises

I'm having trouble returning data from an Angular promise in a factory back to the controller. In this example,

http://jsfiddle.net/c3xjE/

update: function (staffList) {
    // get local last updated timestamp
    var lastUpdatedLocal = "";
    var lastUpdatedRemote = "";
    for (i=0; i < staffList.length; i++) {
        // get largest (most recent) timestamp
        if(staffList[i].entry_date > lastUpdatedLocal) {
            lastUpdatedLocal = staffList[i].entry_date;
        }
    }

// get remote last updated timestamp
var promise = $http.get('REMOTE_API_CALL')
    .success(function(data, status, header, config) {
        return lastUpdatedRemote = data[0].entry_date;
    }).then(function(response) {
        return response.data[0].entry_date;
        });
    console.log(promise);
}

I want to filter local data to get a local timestamp, compare it against a remote timestamp and instruct the controller to re-download all data if the local timestamp is less than the remote timestamp.

I'm filtering the local data okay and getting the expected result. Where I seem to get stuck is with promises. I can log out the filtered remote data within the .success or .then methods but haven't had much luck returning the values out of the promises. I know there's probably an issue with variable scope here.

Also, am I best to return a boolean from my factory to my controller (should I update? true/false) or perhaps a small obj with the local & remote timestamped data and leave the controller decide what to do from there?

Thanks in advance.

Upvotes: 0

Views: 1125

Answers (1)

JimTheDev
JimTheDev

Reputation: 3469

Here is the best example I have of how to implement this. I assumed some stuff about your controller and factory. Note that you need to inject $q into your factory to use deferreds. This is how I do it in my app.

http://jsfiddle.net/JimTheDev/2zLEp/

/*
  NOTE: make sure to inject $q into your factory before
  this. For the purposes of my example, let's assume your
  factory looks like this:
*/
app.factory('mySweetFactory', ['$q', function($q) {
    return {

        // You probably have a bunch of other methods like
        // this one in your factory.
        myothermethod: function(argument1, argument2) { 
            /* some code here */
        },

        update: function (staffList) {

            // Create a new deferred object
            var deferred = $q.defer();

            // get local last updated timestamp
            var lastUpdatedLocal = "";
            for (i=0; i < staffList.length; i++) {
                // get largest (most recent) timestamp
                if(staffList[i].entry_date > lastUpdatedLocal) {
                    lastUpdatedLocal = staffList[i].entry_date;
                }
            }

            // Make a call to the remote api
            $http.get('REMOTE_API_CALL').then(function(response) {

                // Get the remote last updated
                // time from the response
                var lastUpdatedRemote = response.data[0].entry_date;

                // Check if local or remote is larger
                // You probably need to modify this 
                // depending on your datetime formatting. 
                // I am assuming an epoch string.
                if(lastUpdatedRemote > lastUpdatedLocal)
                {
                    // Resolve the deferred and return
                    // the data so that the controller can
                    // use it to update the view
                    deferred.resolve(response.data);
                } else {
                    // Since we don't need to do anything,
                    // reject the deferred
                    deferred.reject();
            });

            // Return the promise from the deferred object
            // immediately. We will eventually either 
            // resolve or reject it, but at the start, it
            // will be in a pending state.
            return deferred.promise;
        }
    };
}]);

app.controller('mySweetController', ['mySweetFactory', function(mySweetFactory){
    $scope.doUpdate = function() {
        mySweetFactory.update($scope.staffList).then(function(newStaffList) {
            // Promise was resolved. List needs updating!
            $scope.staffList = newStaffList;
        }, function(){
            // Promise was rejected. No update needed!
        });
    };
}]);

Upvotes: 2

Related Questions