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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.