Rhs
Rhs

Reputation: 3318

Asynchronous Angular Promise and Variable Initialization

I have a factory that looks like such:

app.factory('thingFactory', function($http) {

    var factory = {};   
    var things = [];

    factory.refreshThings = function() {
        return $http.post('/GetThings');
    }

    factory.initializeThings = factory.refreshThings()
        .then(function(response) {
            things = response.data;
        }, function(response){
            // some error handling code here...
        });

    factory.getThings = function() {
        return things;
    }

    return factory;
}

and a controller

app.controller('myController', function($scope, thingFactory) {
    $scope.things = thingFactory.getThings();
}

Because of the asynchronous nature of promises, and other collections being initialized (in addition to things), should I be concerned with getThings() returning an empty array, and thus, returning before the $http.post() call has resolved?

Is this a better alternative?

app.controller('myController', function($scope, thingFactory) {
    $scope.things = []

    thingFactory.initializeThings
        .then(function(response) {
            $scope.things = response.data;
        }, function (response) {
            // some error handling code here...
        });
}

Is there a safe alternative, where I can get the controller to not think about the promise and just safely get the collection from the factory?

Upvotes: 0

Views: 2438

Answers (1)

EmptyArsenal
EmptyArsenal

Reputation: 7464

You're code is definitely going to be problematic. The factory will not be instantiated until it is used by a controller, so things will not be initialized until it is called by a controller, at which time initializeThings will get called right before you call getThings, which will likely return an empty array. Also, it's never a good idea to follow a "let's hope it's there" approach.

I see two approaches you can take: getThings accepts a callback as an argument or it returns a promise, which could look something like this:

  1. Callbacks - I prefer callbacks over promises, but that's a personal thing. Also, I use NodeJS-inspired syntax:

    var things; // no need to initialize array
    
    // callback -> function (error, things) {}
    factory.getThings = function (callback) {
      if (things) {
        return callback(null, things);
      }
    
      factory.refreshThings()
        .then( function (response) {
            things = response.data;
            return callback(null, things);
        }, function (reason) {
            return callback(reason);
        });
    }
    
  2. Promises - not the best syntax, but you get the idea

    factory.getThings = function () {
      var d = $q.defer();
      // I'm sure there's a better way to do this, but setting
      // this in a timeout will allow the promise to return so that
      // you can try to return it.
      $timeout( function () {
        if (things) {
           return d.resolve(things);
        }
    
        factory.refreshThings()
          .then( function (response) {
            things = response.data;
            return d.resolve(things);
          }, function (reason) {
            return d.reject(reason);
          });
      });
    
      return d.promise;
    }
    

As a side note, if you're using a RESTful API, GET should be used to get information rather than POST.

Upvotes: 1

Related Questions