0

I have one of those "really fat controller" controllers from an MVP of a project, that I'd like to refactor into more modular and compartmentalised code.

At present I have a function in my controller which:

  1. Make an $HTTP call to an API
  2. Processes the returned data with a for loop and a switch statement
  3. Saves it to scope

I'd like to move this to a service. So far I have this:

angular.module('myApp.services', [])
.service('apiService', ['$http', 'webapiBase', function($http, webapiBase) {
  this.getData = function(){
    $http.get(webapiBase + '/api/getData').then(function(res){
      var obj = res.data;
      // Processing stuff
      return obj;
    }, function(err){
      return false;
    })
  }
}]);

In my controller, I need to run a callback when this service returns its data, like:

// In my Service:
this.getData = function(cb){
    $http.get(webapiBase + '/api/getData').then(function(res){
       var obj = res.data; 
       cb(obj);
    }, function(err){
       cb(false);
    })
  }

// In my controller
apiService.getData(function(data){
    $scope.data = data;
    // Do other stuff here
})   

But this feels a bit weird/non-'Angular'.

Is there a more "Angular" way to achieve this, perhaps while using $q?

2 Answers 2

3

You just need to make a small modification to your service

  this.getData = function(){
    return $http.get(webapiBase + '/api/getData').then(function(res){
      // Processing stuff
      return object;
    }, function(err){
      return false;
    })
  }

Return the promise object of $http.get directly. Then in your controller

apiService.getData().then(function(data){
    $scope.data = data;
    // Do other stuff here
})

Edit

If you really don't want to reuse the promise object created by $http, you can create your own real quick.

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

    $http.get(webapiBase + '/api/getData').then(function(res){
      // Processing stuff
      deferred.resolve(object);
    }, function(err){
      deferred.reject('error');
    });

    return deferred.promise;
}
Sign up to request clarification or add additional context in comments.

4 Comments

A little confused - returning the $http.get function as a whole somehow lets me access a then() when I call apiService.getData()?
@Jascination yes, the reason you can execute then against $http.get() is get() will return a promise object. You can create your own using $q but personally I suggest to re-use the promise obj.
I see. So the return in return object is returning to the promise set by $http?
Yes, when you invoke then(function x() {}) against $http.get, function x will be registered in the promise object internally. Once the request is finished and returns an object, the promise object will pass the result to function x.
1

You can use $q to achieve what you're looking for.

// Your service
angular.module('myApp.services', [])
.service('apiService', ['$http', 'webapiBase', function($http, webapiBase) {
  this.getData = function() {
    var deferred = $q.defer();
    $http.get(webapiBase + '/api/getData').then(
        function (res) {
            // Do something with res.data
            deferred.resolve(res.data);
        },
        function(res){
            deferred.reject();
        }
    );
    return deferred.promise;
  }
}]);

Then consume the $q promise in your controller and respond to it:

// Your controller
apiService.getData().then(function(data) {
    $scope.data = data;
    // Do other stuff here
});

That's the Angular-way, using promises with $q.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.