Jonathan H. Jonathan H. - 5 months ago 13
AngularJS Question

Calling $http promise inside controller

Thanks in advance for the help...

I have a controller I'm using to call an API to send a password reset link. I have abstracted the actual $http call off into a service to keep the controller thin. Originally I was doing something like this:

angular.module('module')
.service('forgotPasswordService', ['$http', function($http) {
$http(request).then(function() {
return {}; //return some object using response
}]);


I felt like this would be the best approach as it would keep the controller as thin as possible and kept all service related actions separate. My problem with this was that returning from within the promise never actually returned me anything. I had to actually return the $http service call to get the promise. The only way I was able to make all of this work was if I called .then from within the controller.

//controller
angular.module('module')
.controller('forgotPasswordCtrl', ['forgotPasswordService', function(forgotPasswordService) {
forgotPasswordService.forgotPassword(emailAddress).then(function() {
//do stuff
}
}]);
//service
angular.module('module')
.service('forgotPasswordService', ['$http', function($http){
this.forgotPassword = function(emailAddress) {
return $http(request);
};
}]);


This just feels a little wrong to me because the controller now depends on receiving a promise back from the service. I may just be overthinking this but I would like a second opinion.

Is this considered acceptable/good practice? Is there an alternative to this which would allow me to achieve the encapsulation I'm looking for?

Thanks again.

Answer

I've interfaced with the $http from the controller in two slightly different ways.

Like you it felt wrong returning the $http from the service and interfacing with it.

So first I created services and passed in a success method and an error method (callbacks).

// Service
  angular.module('module')
    .service('forgotPasswordService', ['$http', function($http) {

        function sendForgotPasswordEmail(emailAddress, success, error){
            $http.post('/api/v1/resetpassword', {emailAddress:emailAddress})
            .then(success, error);
        }

      return {
        sendForgotPasswordEmail: sendForgotPasswordEmail
      }
}]);

// Controller
angular.module('module')
    .controller('forgotPasswordCtrl', ['forgotPasswordService', function(forgotPasswordService) {

        forgotPasswordService.sendForgotPasswordEmail(emailAddress, 
        function(response){ //success
          // notify user of success
        },
        function(response){ // error
          // notify user of error
        });
}]);

This worked great. I created an large application this way, but as I started on my second large angular project I wondered why I was hiding the $http's promise?

By passing back the promise, I can use other libraries that support promises. With my first approach I can't leverage other libraries promise support.

Passing back the $http promise

// Service
  angular.module('module')
    .service('forgotPasswordService', ['$http', function($http) {

        function sendForgotPasswordEmail(emailAddress){
          return $http.post('/api/v1/resetpassword', {emailAddress:emailAddress});
        }

      return {
        sendForgotPasswordEmail: sendForgotPasswordEmail
      }
}]);

// Controller
angular.module('module')
    .controller('forgotPasswordCtrl', ['forgotPasswordService', function(forgotPasswordService) {

        forgotPasswordService.sendForgotPasswordEmail(emailAddress)
        .then(
              function(response){ //success
                // notify user of success
              },
              function(response){ // error
                // notify user of error
              });
}]);